makefile編寫



自動生成依賴性

在Makefile中,我們的依賴關係可能會需要包含一系列的頭文件,比如,如果我們的main.c中有一句“#include "defs.h"”,那麼我們的依賴關係應該是:

main.o : main.c defs.h

但是,如果是一個比較大型的工程,你必需清楚哪些C文件包含了哪些頭文件,並且,你在加入或刪除頭文件時,也需要小心地修改Makefile,這是一個很沒有維護性的工作。爲了避免這種繁重而又容易出錯的事情,我們可以使用C/C++編譯的一個功能。大多數的C/C++編譯器都支持一個“-M”的選項,即自動找尋源文件中包含的頭文件,並生成一個依賴關係。例如,如果我們執行下面的命令:

cc -M main.c

其輸出是:

main.o : main.c defs.h

於是由編譯器自動生成的依賴關係,這樣一來,你就不必再手動書寫若干文件的依賴關係,而由編譯器自動生成了。需要提醒一句的是,如果你使用GNU的C/C++編譯器,你得用“-MM”參數,不然,“-M”參數會把一些標準庫的頭文件也包含進來。

gcc -M main.c的輸出是:

main.o: main.c defs.h /usr/include/stdio.h /usr/include/features.h \
    /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \
    /usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h \
    /usr/include/bits/types.h /usr/include/bits/pthreadtypes.h \
    /usr/include/bits/sched.h /usr/include/libio.h \
    /usr/include/_G_config.h /usr/include/wchar.h \
    /usr/include/bits/wchar.h /usr/include/gconv.h \
    /usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h \
    /usr/include/bits/stdio_lim.h


gcc -MM main.c的輸出則是:

main.o: main.c defs.h

那麼,編譯器的這個功能如何與我們的Makefile聯繫在一起呢。因爲這樣一來,我們的Makefile也要根據這些源文件重新生成,讓 Makefile自已依賴於源文件?這個功能並不現實,不過我們可以有其它手段來迂迴地實現這一功能。GNU組織建議把編譯器爲每一個源文件的自動生成的依賴關係放到一個文件中,爲每一個“name.c”的文件都生成一個“name.d”的Makefile文件,[.d]文件中就存放對應[.c]文件的依賴關係。

於是,我們可以寫出[.c]文件和[.d]文件的依賴關係,並讓make自動更新或自成[.d]文件,並把其包含在我們的主Makefile中,這樣,我們就可以自動化地生成每個文件的依賴關係了。

這裏,我們給出了一個模式規則來產生[.d]文件:

%.d: %.c
	@set -e; rm -f $@; \
         $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
         sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
         rm -f $@.$$$$


這個規則的意思是,所有的[.d]文件依賴於[.c]文件,“rm -f $@”的意思是刪除所有的目標,也就是[.d]文件,第二行的意思是,爲每個依賴文件“$<”,也就是[.c]文件生成依賴文件,“$@”表示模式“%.d”文件,如果有一個C文件是name.c,那麼“%”就是 “name”,“$$$$”意爲一個隨機編號,第二行生成的文件有可能是“name.d.12345”,第三行使用sed命令做了一個替換,關於sed命令的用法請參看相關的使用文檔。第四行就是刪除臨時文件。

總而言之,這個模式要做的事就是在編譯器生成的依賴關係中加入[.d]文件的依賴,即把依賴關係:

main.o : main.c defs.h

轉成:

main.o main.d : main.c defs.h

於是,我們的[.d]文件也會自動更新了,並會自動生成了,當然,你還可以在這個[.d]文件中加入的不只是依賴關係,包括生成的命令也可一併加入,讓每個[.d]文件都包含一個完賴的規則。一旦我們完成這個工作,接下來,我們就要把這些自動生成的規則放進我們的主Makefile中。我們可以使用Makefile的“include”命令,來引入別的Makefile文件(前面講過),例如:

sources = foo.c bar.c

include $(sources:.c=.d)

上述語句中的“$(sources:.c=.d)”中的“.c=.d”的意思是做一個替換,把變量$(sources)所有[.c]的字串都替換成[.d],關於這個“替換”的內容,在後面我會有更爲詳細的講述。當然,你得注意次序,因爲include是按次來載入文件,最先載入的[.d]文件中的目標會成爲默認目標。




#file start

SOURCES = $(wildcard *.c)

OBJS := $(patsubst %.c,%.o, $(SOURCES))

 

all: main

 

%.d: %.c

        @set -e; rm -f $@;\

        $(CC) -MM  $< > $@.$$$$; \

        sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ > $@; \

        rm -f $@.$$$$

 

sinclude $(SOURCES:.c=.d)

 

main:$(OBJS)

        $(CC) -o main $(OBJS)

 

clean:

        rm -f *.o test *.d

#file end




gcc include路徑  

2009-12-07 16:18:54|  分類:編程 |舉報|字號 訂閱

《GCC:the complete referrence》說,gcc的include有以下幾個組成:

On a UNIX system, the standard set of system directories is as follows:
/usr/local/include
/usr/lib/gcc-lib/target/version/include
/usr/target/include
/usr/include

通過 gcc -v   *.c 可以看編譯時具體過程:
[hyang0@pek-wb-auto ~]$ gcc -v hello.c
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man--infodir=/usr/share/info --enable-shared --enable-threads=posix--enable-checking=release --with-system-zlib --enable-__cxa_atexit--disable-libunwind-exceptions --enable-libgcj-multifile--enable-languages=c,c++,objc,obj-c++,java,fortran,ada--enable-java-awt=gtk --disable-dssi --enable-plugin--with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre--with-cpu=generic --host=i386-redhat-linux
Thread model: posix
gcc version 4.1.1 20070105 (Red Hat 4.1.1-52)
/usr/libexec/gcc/i386-redhat-linux/4.1.1/cc1 -quiet -v hello.c -quiet-dumpbase hello.c -mtune=generic -auxbase hello -version -o/tmp/ccPUf6Jg.s
ignoring nonexistent directory "/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../i386-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/lib/gcc/i386-redhat-linux/4.1.1/include
/usr/include
End of search list.

GNU C version 4.1.1 20070105 (Red Hat 4.1.1-52) (i386-redhat-linux)
compiled by GNU C version 4.1.1 20070105 (Red Hat 4.1.1-52).
GGC heuristics: --param ggc-min-expand=98 --param ggc-min-heapsize=129176
Compiler executable checksum: 92efef273c2911dfe2bff20f05a618b3
as -V -Qy -o /tmp/ccEed4Cr.o /tmp/ccPUf6Jg.s
GNU assembler version 2.17.50.0.6-2.el5 (i386-redhat-linux) using BFD version 2.17.50.0.6-2.el5 20061020
/usr/libexec/gcc/i386-redhat-linux/4.1.1/collect2 --eh-frame-hdr -melf_i386 --hash-style=gnu -dynamic-linker /lib/ld-linux.so.2/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../crt1.o/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../crti.o/usr/lib/gcc/i386-redhat-linux/4.1.1/crtbegin.o-L/usr/lib/gcc/i386-redhat-linux/4.1.1-L/usr/lib/gcc/i386-redhat-linux/4.1.1-L/usr/lib/gcc/i386-redhat-linux/4.1.1/../../.. /tmp/ccEed4Cr.o -lgcc--as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s--no-as-needed /usr/lib/gcc/i386-redhat-linux/4.1.1/crtend.o/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../crtn.o
[hyang0@pek-wb-auto ~]$

可以看到search過程:
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/usr/lib/gcc/i386-redhat-linux/4.1.1/include
/usr/include
End of search list.

如果要添加查找路徑:
The following is a list of the environment variables that can be set to pass instructions
to the preprocessor.

C_INCLUDE_PATH, CPATH, CPLUS_INCLUDE_PATH, DEPENDENCIES_OUTPUT,
OBJC_INCLUDE_PATH, SUNPRO_DEPENDENCIES

對所有用戶有效在/etc/profile增加以下內容。只對當前用戶有效在Home目錄下的
.bashrc或.bash_profile裏增加下面的內容:
(注意:等號前面不要加空格,否則可能出現 command not found)

#在PATH中找到可執行文件程序的路徑。
export PATH =$PATH:$HOME/bin

#gcc找到頭文件的路徑
C_INCLUDE_PATH=/usr/include/libxml2:/MyLib
export C_INCLUDE_PATH #(可在makefile中)

#g++找到頭文件的路徑
CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/include/libxml2:/MyLib
export CPLUS_INCLUDE_PATH

#找到動態鏈接庫的路徑
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/MyLib
export LD_LIBRARY_PATH

#找到靜態庫的路徑
LIBRARY_PATH=$LIBRARY_PATH:/MyLib
export LIBRARY_PATH

連接器ld搜索路徑和順序
bash$  ld --verbose | grep SEARCH
SEARCH_DIR("/usr/i486-linux-gnu/lib32");SEARCH_DIR("/usr/local/lib32"); SEARCH_DIR("/lib32");SEARCH_DIR("/usr/lib32"); SEARCH_DIR("/usr/i486-linux-gnu/lib");SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib");SEARCH_DIR("/usr/lib");
bash$ 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章