在下面的三個(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腳本方面的東西。
首先要做的事情是創(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,因?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)單的事情都做不好的編輯器。