Win7 命令行下C語言學習環境搭建(三)


從上次碰到編譯鏈接帶有自定義庫的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 目標”  就能生成我們需要的一鍵編譯生成可執行文件。我們目前還是停留在我上一篇的老問題上,如圖所示:

image_thumb7

如果GCC能正常進行,而make卻不能有效工作,我們需要研究makefile文件的編寫了!

Makefile 文件的編寫

(一)基本規則、命令書寫

clip_image001clip_image002clip_image003

這是我在office 2013 Word 中截取的圖片,其中可以看到TAB鍵。如果依賴文件比較多,也可以”\””;”處理

2.基本示例及說明:

  • 這個 #  用於注釋
  • main 是“目標”;后面 .o 文件是它的依賴文件
  • .o 文件各自又依賴相應的 .c .h 文件
  • clean: 這個目標沒有依賴,目的在於執行下面的命令

如果當前文件夾下面存在一個名為clean的文件,這個命令就不會執行了,因為沒有依賴,make認為這個clean文件始終是最新的,不符合更新的條件。為了避免這種情況,一般在makefile文件中指定clean為偽目標     .PHONY clean

# ========BASIC VERSION =================
main:main.o add.o sub.o
    gcc main.o add.o sub.o -o main
main.o:main.c add.h sub.h
    gcc -c main.c -o main.o
add.o:add.c add.h
    gcc -c add.c -o add.o
sub.o:sub.c sub.h
    gcc -c sub.c -o sub.o
clean:
    del main.exe main.o add.o sub.o
# ========================================

3.自定義變量與自動化變量

OBJ 是自定義變量,引用變量時用“$(   )”的方式


$@ —— 代表目標
$< —— 當前目標的第一個依賴文件
$^ —— 當前目標的所有依賴文件

# ====== version 1 ======
OBJ=main.o add.o sub.o
main:$(OBJ)
    gcc $(OBJ) -o $@
main.o:main.c add.h sub.h
    gcc -c $< -o $@
add.o:add.c add.h
    gcc -c $< -o $@
sub.o:sub.c sub.h
    gcc -c $< -o $@
clean:
    del *.o *.exe
# =======================

(二)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 $@ 這個順序需要引起高度重視!如果這兩個變量弄反了……后果會很嚴重,嘿嘿。

image

在這個例子中,$^表示的是hi3.c $@表示的是hi3   -lcs50 在 $^ 前還是后的位置影響編譯鏈接結果!

  • 最初錯誤的設置,您看出來了么?
  • CS50 學習環境的正確的設置是這樣的

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 hi3

vpath %.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 ,我不知道這是什么原因:

image

唉,目前不知道從哪入手來想……以后再說了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM