鍍金池/ 教程/ C/ 練習(xí)28:Makefile 進(jìn)階
練習(xí)9:數(shù)組和字符串
練習(xí)6:變量類型
練習(xí)3:格式化輸出
練習(xí)4:Valgrind 介紹
練習(xí)28:Makefile 進(jìn)階
練習(xí)14:編寫并使用函數(shù)
練習(xí)21:高級(jí)數(shù)據(jù)類型和控制結(jié)構(gòu)
練習(xí)20:Zed的強(qiáng)大的調(diào)試宏
練習(xí)18:函數(shù)指針
練習(xí)0:準(zhǔn)備
練習(xí)15:指針,可怕的指針
練習(xí)27:創(chuàng)造性和防御性編程
練習(xí)22:棧、作用域和全局
練習(xí)10:字符串?dāng)?shù)組和循環(huán)
練習(xí)8:大小和數(shù)組
練習(xí)16:結(jié)構(gòu)體和指向它們的指針
練習(xí)7:更多變量和一些算術(shù)
練習(xí)23:認(rèn)識(shí)達(dá)夫設(shè)備
練習(xí)12:If,Else If,Else
練習(xí)2:用Make來(lái)代替Python
練習(xí)1:?jiǎn)⒂镁幾g器
練習(xí)11:While循環(huán)和布爾表達(dá)式
練習(xí)5:一個(gè)C程序的結(jié)構(gòu)
練習(xí)24:輸入輸出和文件
練習(xí)25:變參函數(shù)
練習(xí)13:Switch語(yǔ)句
練習(xí)19:一個(gè)簡(jiǎn)單的對(duì)象系統(tǒng)
練習(xí)26:編寫第一個(gè)真正的程序
導(dǎo)言:C的笛卡爾之夢(mèng)
練習(xí)17:堆和棧的內(nèi)存分配

練習(xí)28:Makefile 進(jìn)階

在下面的三個(gè)練習(xí)中你會(huì)創(chuàng)建一個(gè)項(xiàng)目的目錄框架,用于構(gòu)建之后的C程序。這個(gè)目錄框架會(huì)在這本書中剩余的章節(jié)中使用,并且這個(gè)練習(xí)中我會(huì)涉及到Makefile便于你理解它。

這個(gè)結(jié)構(gòu)的目的是,在不憑借配置工具的情況下,使構(gòu)建中等規(guī)模的程序變得容易。如果完成了它,你會(huì)學(xué)到很多GNU make和一些小型shell腳本方面的東西。

基本的項(xiàng)目結(jié)構(gòu)

首先要做的事情是創(chuàng)建一個(gè)C的目錄狂阿基,并且放置一些多續(xù)項(xiàng)目都擁有的,基本的文件和目錄。這是我的目錄:

$ mkdir c-skeleton
$ cd c-skeleton/
$ touch LICENSE README.md Makefile
$ mkdir bin src tests
$ cp dbg.h src/   # this is from Ex20
$ ls -l
total 8
-rw-r--r--  1 zedshaw  staff     0 Mar 31 16:38 LICENSE
-rw-r--r--  1 zedshaw  staff  1168 Apr  1 17:00 Makefile
-rw-r--r--  1 zedshaw  staff     0 Mar 31 16:38 README.md
drwxr-xr-x  2 zedshaw  staff    68 Mar 31 16:38 bin
drwxr-xr-x  2 zedshaw  staff    68 Apr  1 10:07 build
drwxr-xr-x  3 zedshaw  staff   102 Apr  3 16:28 src
drwxr-xr-x  2 zedshaw  staff    68 Mar 31 16:38 tests
$ ls -l src
total 8
-rw-r--r--  1 zedshaw  staff  982 Apr  3 16:28 dbg.h
$

之后你會(huì)看到我執(zhí)行了ls -l,所以你會(huì)看到最終結(jié)果。

下面是每個(gè)文件所做的事情:

LICENSE

如果你在項(xiàng)目中發(fā)布源碼,你會(huì)希望包含一份協(xié)議。如果你不這么多,雖然你有代碼的版權(quán),但是通常沒(méi)有人有權(quán)使用。

README.md

對(duì)你項(xiàng)目的簡(jiǎn)要說(shuō)明。它以.md結(jié)尾,所以應(yīng)該作為Markdown來(lái)解析。

Makefile

這個(gè)項(xiàng)目的主要構(gòu)建文件。

bin/

放置可運(yùn)行程序的地方。這里通常是空的,Makefile會(huì)在這里生成程序。

build/

當(dāng)值庫(kù)和其它構(gòu)建組件的地方。通常也是空的,Makefile會(huì)在這里生成這些東西。

src/

放置源碼的地方,通常是.c.h文件。

tests/

放置自動(dòng)化測(cè)試的地方。

src/dbg.h

我將練習(xí)20的dbg.h復(fù)制到了這里。

我剛才分解了這個(gè)項(xiàng)目框架的每個(gè)組件,所以你應(yīng)該明白它們?cè)趺垂ぷ鳌?/p>

Makefile

我要講到的第一件事情就是Makefile,因?yàn)槟憧梢詮闹辛私馄渌鼥|西的情況。這個(gè)練習(xí)的Makeile比之前更加詳細(xì),所以我會(huì)在你輸入它之后做詳細(xì)的分解。

CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(OPTFLAGS)
LIBS=-ldl $(OPTLIBS)
PREFIX?=/usr/local

SOURCES=$(wildcard src/**/*.c src/*.c)
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))

TEST_SRC=$(wildcard tests/*_tests.c)
TESTS=$(patsubst %.c,%,$(TEST_SRC))

TARGET=build/libYOUR_LIBRARY.a
SO_TARGET=$(patsubst %.a,%.so,$(TARGET))

# The Target Build
all: $(TARGET) $(SO_TARGET) tests

dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS)
dev: all

$(TARGET): CFLAGS += -fPIC
$(TARGET): build $(OBJECTS)
       ar rcs $@ $(OBJECTS)
       ranlib $@

$(SO_TARGET): $(TARGET) $(OBJECTS)
       $(CC) -shared -o $@ $(OBJECTS)

build:
       @mkdir -p build
       @mkdir -p bin

# The Unit Tests
.PHONY: tests
tests: CFLAGS += $(TARGET)
tests: $(TESTS)
       sh ./tests/runtests.sh

valgrind:
       VALGRIND="valgrind --log-file=/tmp/valgrind-%p.log" $(MAKE)

# The Cleaner
clean:
       rm -rf build $(OBJECTS) $(TESTS)
       rm -f tests/tests.log
       find . -name "*.gc*" -exec rm {} \;
       rm -rf `find . -name "*.dSYM" -print`

# The Install
install: all
       install -d $(DESTDIR)/$(PREFIX)/lib/
       install $(TARGET) $(DESTDIR)/$(PREFIX)/lib/

# The Checker
BADFUNCS='[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)|stpn?cpy|a?sn?printf|byte_)'
check:
       @echo Files with potentially dangerous functions.
       @egrep $(BADFUNCS) $(SOURCES) || true

要記住你應(yīng)該使用一致的Tab字符來(lái)縮進(jìn)Makefile。你的編輯器應(yīng)該知道怎么做,但是如果不是這樣你可以換個(gè)編輯器。沒(méi)有程序員會(huì)使用一個(gè)連如此簡(jiǎn)單的事情都做不好的編輯器。

頭文件