從上次碰到編譯鏈接帶有自定義庫的C源文件后,就停止了學習,工作時間瞎忙,這一個多點星期以來,老問題又重新涌上腦際,查閱了好多與 Makefile Gcc 相關的網頁資料,終於搞明白了相關的原因,記錄下這一過程中遇到的一些困難與問題,以資分享。
GCC 環境變量
在搭建好基本軟件后,您還需要注意一些細節問題,重要的是環境變量的設置,用於幫助我們准確找到你的源文件中包括的用戶自義函數庫,以及頭文件。-->頭文件.h 庫文件.lib .a
- 環境變量與Gcc編譯錯誤
環境變量中沒有定義:
C_INCLUDE_PATH=E:\cs50\include --->頭文件具體位置,所在路徑
LIBRARY_PATH=E:\cs50\lib ---->庫文件具體位置,.lib 或者 .a 文件
注意:LIBRARY_PATH C_INCLUDE_PATH 這兩個為GCC編譯時使用的.h,.a文件所在目錄,名稱似乎不能胡亂更改。
假設源文件hi3.c包括了自定義庫 libcs50.a 也即 #include “cs50.h”。我們在命令行下可以嘗試下——
#=========== 沒有C_INCLUDE_PATH ===========
C:\Users\Administrator>gcc hi3.c -o hi3
hi3.c:2:18: fatal error: cs50.h: No such file or directory
compilation terminated.
#=========== 設置好 LIBRARY_PATH C_INCLUDE_PATH ,但沒有指明 -lcs50 ===========
C:\Users\Administrator>gcc hi3.c -o hi3
C:\Users\ADMINI~1\AppData\Local\Temp\ccitQVf8.o:hi3.c:(.text+0x1b): undefined reference to `GetString'
collect2.exe: error: ld returned 1 exit status
#=========== 命令中加上 -lcs50 成功 ===========
C:\Users\Administrator>gcc hi3.c -o hi3 -lcs50
C:\Users\Administrator>
# ============================================
可見,在編譯與鏈接過程中,這兩個變量將產生實際的影響。當然,您也可以在使用過程中自己指出具體路徑
C:\Users\Administrator>gcc hi3.c –IE:\cs50\include –LE:\cs50\lib -o hi3 -lcs50
C:\Users\Administrator>
“-I” 和“-L” 兩個分別是編譯和鏈接時,找尋.h文件、.a文件的具體路徑
總的來說,只要設置好這兩個變量,CS50學習環境下就可以自由地運行GCC了。但我們的目標是,直接“make 目標” 就能生成我們需要的一鍵編譯生成可執行文件。我們目前還是停留在我上一篇的老問題上,如圖所示:
如果GCC能正常進行,而make卻不能有效工作,我們需要研究makefile文件的編寫了!
Makefile 文件的編寫
(一)基本規則、命令書寫
這是我在office 2013 Word 中截取的圖片,其中可以看到TAB鍵。如果依賴文件比較多,也可以”\””;”處理
2.基本示例及說明:
如果當前文件夾下面存在一個名為clean的文件,這個命令就不會執行了,因為沒有依賴,make認為這個clean文件始終是最新的,不符合更新的條件。為了避免這種情況,一般在makefile文件中指定clean為偽目標 .PHONY clean |
# ========BASIC VERSION ================= |
3.自定義變量與自動化變量 OBJ 是自定義變量,引用變量時用“$( )”的方式 |
# ====== version 1 ====== |
(二)makefile自動推導規則(與C語言相關的)
你可以在命令行下打:"make -p >view.txt” 然后打開view.txt 查看有關內置規則(# Implicit Rule)
%: %.c
# recipe to execute (built-in):
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@
我想這條就是內置將.c文件生成.exe可執行文件的內置規則
# default
LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
多看看make 的幫助文件,是學習的好途徑!由上面我們可以看出,如果在環境變量中設置這些變量的值,我們就可以做到“定制”默認的make方式了,這就可以完成CS50學習環境的設置了!!!將 LINK.c 代入$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $@ 擴展開來就像下面這樣了:
%: %.c <====表示直接將.c 源文件編譯鏈接成可執行文件(.exe )
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@
如果您的環境變量中沒有設置相應的值,make 默認的表現會是:cc hi3.c –o hi3 我們可以利用這一特性,“改變”內置規則的外在表現以符合我們自己的特殊需要。注意:根據上面的擴展可知 $(LDFLAGS)$^$(LDLIBS)-o $@ 這個順序需要引起高度重視!如果這兩個變量弄反了……后果會很嚴重,嘿嘿。
在這個例子中,$^表示的是hi3.c $@表示的是hi3 -lcs50 在 $^ 前還是后的位置影響編譯鏈接結果!
|
|
CC=gcc CFLAGS=-ggdb -std=c99 -Wall -Werror -Wformat=0 CPPFLAGS=-IE:\CS50\INCLUDE LDLIBS=-LE:\CS50\LIB LDFLAGS=-lcs50 -lm |
CC=gcc CFLAGS=-ggdb -std=c99 -Wall -Werror -Wformat=0 LDLIBS=-lcs50 -lm CPPFLAGS=-IE:\CS50\INCLUDE LDFLAGS=-LE:\CS50\LIB |
如果環境變量中已經設置了CPPFLAGS=-IE:\CS50\INCLUDE 和LDFLAGS=-LE:\CS50\LIB 那么,makefile 文件里面就可以只設置 CC CFLAGS LDLIBS 三個即可。 |
CC=gcc CFLAGS=-ggdb -std=c99 -Wall -Werror -Wformat=0 LDLIBS=-lcs50 -lm |
(三)初學者適用的makefile文件
初學者習慣於在一個目錄中練習自己編寫好的C語言源文件,網上文章中習慣介紹這樣一種makefile文件放在練習目錄之中:
.PHONY:clean all
CC=gcc
CFLAGS=-g -Wall
BIN=hi1 hi2 hi3vpath %.h E:\cs50\include
vpath %.a E:\cs50\lib
all:$(BIN).c.o:
$(CC) $(CFLAGS) -c $< -o $@
hi1:hi1.o
$(CC) $(CFLAGS) $^ -o $@
hi2:hi2.o cs50.h
$(CC) $(CFLAGS) $^ -o $@
hi3:hi3.o cs50.h -lcs50
$(CC) $(CFLAGS) $^ -o $@
clean:
del *.o *.exe
這樣的makefile比較清楚,但每次新的測試文件加入后,需要手動添加需要編譯的新文件,有點“麻煩”,考慮到這一點,我們可以利用上面makefile的自動推導規則,通過對環境變量的設置,定制“萬能”一些的makefile文件:
.PHONY:clean all
CC=gcc
CFLAGS=-ggdb -std=c99 -Wall -Werror -Wformat=0
#CPPFLAGS=-IE:\cs50\include
#LDFLAGS=-LE:\cs50\lib
LDLIBS=-lcs50 -lm
OBJS=$(patsubst %.c,%.o,$(wildcard *.c))
BIN=$(basename $(OBJS))
all:$(BIN)clean:
del *.o *.exe
到此,我們可以做到像CS50課堂中那樣,make “目標” 就能自動處理了。
環境變量的設置可以做成一個注冊個文件,導入一下就行:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Session Manager\Environment]
"C_INCLUDE_PATH"="E:\\cs50\\include"
"CC"="gcc"
"CFLAGS"="-ggdb -std=c99 -Wall -Werror -Wformat=0"
"CPPFLAGS"="-IE:\\cs50\\include"
"LDFLAGS"="-LE:\\cs50\\lib"
"LDLIBS"="-lcs50 -lm"
"LIBRARY_PATH"="E:\\cs50\\lib"
以上內容用記事本保存成 .reg 文件,雙擊導入即可完成設置,當然您需要根據自己的實際情況加以修改。
GCC –MM 顯示的問題
一個遺留問題:hi3.c 源文件中明明引用了cs50.h文件,按理GCC –MM –hi3.c 后,會顯示:hi3.o:hi3.c cs50.h 但實際上卻只顯示 hi3.o:hi3.c ,我不知道這是什么原因:
唉,目前不知道從哪入手來想……以后再說了。