1. 程式人生 > >多目錄Makefile(庫及分層目錄)

多目錄Makefile(庫及分層目錄)

本文程式碼雖簡單,但涉及比較複雜的各種呼叫關係,欲研究者需有耐心及清醒頭腦。 切切!

背景交待:

1、正在移植U-Boot,並對其原始碼進行了一些分析,感覺它的Makefile十分強勁; 2、以前寫的Makefile模板不合適多層目錄; 3、研究一下多個庫之間相互呼叫的問題。 平臺及測試環境介紹: 1、fc9系統,i386平臺,gcc版本4.3.2,使用Secure CRT連線linux系統,資料均由該軟體複製而得; 2、工程目錄名稱為lib-test,其下有3個程式碼目錄及一個頭檔案目錄,分別是foo(foo.c及common.c檔案)、bar(bar.c及common.c檔案)、bt(backtrace.c檔案)和configs(foo.h、bar.h及backtrace.h檔案);其中bt目錄為backtrace程式碼,它是作者的工程庫的一部分。 目錄路徑、檔案分佈如下:
lib-test
|-->main.c
|-->example.c
|-->Makefile
|              |-->foo.c
|-->foo-->|-->common.c
|              |-->Makefile
|
|               |-->bar.c
|-->bar-->|-->common.c
|               |-->Makefile
|
|              |-->backtrace.c
|-->bt--->|
|              |-->Makefile
|
|                   |-->foo.h
|-->configs->|-->bar.h
|                   |-->backtrace.h
Makefile組織 1、各個子目錄單獨使用Makefile,主要生成相關的庫(這裡特指靜態庫); 2、頂層Makefile負責將本目錄下原始碼檔案編譯成目標檔案(如果有的話),並依次進入各種子目錄編譯生成相關庫檔案,最後進行連結,生成可執行檔案。該Makefile關鍵語句如下:
for dir in $(SUBDIRS); \
do $(MAKE) -C $$dir all || exit 1; \
done
意思是進入指定子目錄,並執行子目錄的Makefile檔案(子目錄只負責生成庫檔案)。 庫相互呼叫測試(詳見程式碼): 1、foo.c檔案中hello_foo函式呼叫bar.c檔案中的bar函式以及同一目錄下common.c檔案的common_bar函式; 2、bar.c檔案中hello_bar函式呼叫foo.c檔案中的foo函式以及同一目錄下common.c檔案的common_foo函式。 程式碼示例: 1、foo目錄下: 1)、foo.h
#ifndef
 FOO_H_
#define FOO_H_
void foo(int i);
int hello_foo(void);
#endif
2)、foo.c
#include <stdio.h>
void foo(int i)
{
        printf("hell from %s() in file: %s, num:%d\n", __func__, __FILE__, i);
}
int hello_foo(void)
{
        printf("in func: %s()\n", __func__);
        bar(100);
        common_foo();
        printf("=========================================\n"
);
        return 0;
}
3)、common.c
#include <stdio.h>
int common_foo(void)
{
        printf("this is a common function in foo/common.c\n");
        return 0;
}
2、bar目錄 1)、bar.h
#ifndef BAR_H_
#define BAR_H_
void bar(int i);
int hello_bar(void);
#endif
2)、bar.c
#include <stdio.h>
void bar(int i)
{
        printf("hell from %s() in file: %s, num:%d\n", __func__, __FILE__, i);
}
int hello_bar(void)
{
        printf("in func: %s()\n", __func__);
        foo(200);
        common_bar();
        printf("=========================================\n");
        return 0;
}
3)、common.c
#include <stdio.h>
int common_bar(void)
{
        printf("this is a common function in bar/common.c\n");
        return 0;
}
3、example.c
#include <stdio.h>
void foo1(int a)
{
        int i;
        i = a;
}
int fun(int a, int b, int c)
{
        char buf[14];
        int sum;
        sum = a + b + c;
        foo1(a);
        return sum;
}
4、main.c
#include <stdio.h>
#include <backtrace.h>
#include <foo.h>
#include <bar.h>
int main(void)
{
        printf("hello from %s()\n\n", __func__);
        hello_foo();
        hello_bar();
       
        print_trace(11);
}
(題外話: 這裡的3個自定義標頭檔案使用了尖括號(<>),如果按教科書的說法是不正確的,因為尖括號是從標準庫的路徑搜尋標頭檔案的。然而作者經常看到一些程式碼中標準庫的標頭檔案是使用雙引號來包含的(如#include "stdio.h"),這裡反其道而行之。因為在Makefile中使用-I選項指定了額外的標頭檔案路徑,使用
[[email protected] lib-test-latelee.org]$ gcc -g -c main.c example.c --verbose -Iconfigs
命令來編譯時顯示了gcc搜尋標頭檔案路徑的過程,如下:
#include "..." search starts here: 
#include <...> search starts here: 
 configs
 /usr/local/include 
 /usr/lib/gcc/i386-redhat-linux/4.3.2/include 
 /usr/include 
End of search list.
當然,實際開發中不提倡這種方法,然而在U-Boot中卻是十分常見的,只是有些人不明白其中的道理罷了。 題外話 結束) 庫目錄的Makefile(這裡顯示的是foo目錄下的Makefile,其它者修改庫名稱及程式碼檔名稱即可)
# A simple Makefile for lib(libxxx.a)  
# By Late Lee(http://www.latelee.org)  
AR = ar
ARFLAGS = cr
LIB = libfoo.a
RM = -rm -rf
OBJS := foo.o common.o

all: $(LIB)
$(LIB)$(OBJS)
        $(AR) $(ARFLAGS) [email protected] $(OBJS)
clean:
        $(RM) $(OBJS) $(LIB) *.bak *~
.PHONY: all clean
頂層目錄的Makefile檔案
#################################################################  
# A simple Makefile  
# By Late Lee(http://www.latelee.org)  

#   
# bugs:  
#      1. 需要顯式指定庫位置、名稱;  
#      2. make 及 make clean處理得不好(對於庫,要麼刪除再編譯,要麼無操作);  
#################################################################  

CC=gcc
CFLAGS = -Wall
DEBUG = y

ifeq ($(DEBUG), y)
CFLAGS += -g
else
CFLAGS += -O2
endif

SUBDIRS := foo bar bt

LIBS := bt/libbt.a foo/libfoo.a bar/libbar.a

LDFLAGS = $(LIBS)

RM = -rm -rf

__OBJS = main.o
__OBJS += example.o

__SRCS = $(subst .o,.c,$(__OBJS))

target = a.out

MAKE = make

#all: clean $(target)  
all: $(target)

$(__OBJS)$(__SRCS)
        $(CC) $(CFLAGS) -c $^ -I ./configs/

$(target)$(__OBJS)
        for dir in $(SUBDIRS); \
        do $(MAKE) -C $$dir all || exit 1; \
        done
        $(CC) $(CFLAGS) $^ -o [email protected] $(LDFLAGS)

clean:
        @for dir in $(SUBDIRS)do make -C $$dir clean|| exit 1; done
        $(RM) $(__OBJS) $(target) *.bak *~

.PHONY: all clean 
執行make的過程:
[[email protected] lib-test]$ make 
gcc -Wall -g -c main.c example.c -I ./configs/ 
example.c: In function ‘fun’:
example.c:10: warning: unused variable ‘buf’
for dir in foo bar bt  ; \ 
        do make -C $dir all || exit 1  ; \ 
        done
make[1]: Entering directory `/home/latelee/linux-c/lib-test/foo' 
cc    -c -o foo.o foo.c
cc    -c -o common.o common.c
ar cr libfoo.a foo.o common.o
make[1]: Leaving directory `/home/latelee/linux-c/lib-test/foo' 
make[1]: Entering directory `/home/latelee/linux-c/lib-test/bar' 
cc    -c -o bar.o bar.c
cc    -c -o common.o common.c
ar cr libbar.a bar.o common.o
make[1]: Leaving directory `/home/latelee/linux-c/lib-test/bar' 
make[1]: Entering directory `/home/latelee/linux-c/lib-test/bt' 
cc    -c -o backtrace.o backtrace.c
ar cr libbt.a backtrace.o
make[1]: Leaving directory `/home/latelee/linux-c/lib-test/bt' 
gcc -Wall -g main.o example.o -o a.out bt/libbt.a foo/libfoo.a bar/libbar.a
執行結果:
[[email protected] lib-test]$ ./a.out 
hello from main()
in func: hello_foo()
hell from bar() in file: bar.c, num:100
this is a common function in foo/common.c 
=========================================
in func: hello_bar()
hell from foo() in file: foo.c, num:200
this is a common function in bar/common.c 
=========================================
Obtained 4 stack frames.
./a.out [0x8048733] 
./a.out [0x80486cf] 
/lib/libc.so.6(__libc_start_main+0xe5) [0x7ea6d5] 
./a.out [0x8048601]
歡迎指正文中錯誤之處。其它Makefile高階應用,歡迎一起討論,共同進步。

相關推薦

目錄Makefile(分層目錄)

本文程式碼雖簡單,但涉及比較複雜的各種呼叫關係,欲研究者需有耐心及清醒頭腦。 切切! 背景交待: 1、正在移植U-Boot,並對其原始碼進行了一些分析,感覺它的Makefile十分強勁; 2、以前寫的Makefile模板不合適多層目錄; 3、研究一下多個庫之間相互

Caffe的依賴原始碼目錄結構

1. Boost庫:它是一個可移植、跨平臺,提供原始碼的C++庫,作為標準庫的後備。 在Caffe中用到的Boost標頭檔案包括: (1)、shared_ptr.hpp:智慧指標,使用它可以不需要考慮記憶體釋放的問題; (2)、date_time/posix_tim

linux目錄結構介紹重要目錄說明

內存信息 使用 cpu -h 超級用戶 全局環境變量 ifup 日誌 啟動命令 根節點:/,所有文件都掛載在這下面,目錄結構和分區設備是沒有關系的,不同的目錄可以跨越不同磁盤設備和分區1、查看分區:[root@yangxp Downloads]# ls /dev/sda*/

CMakeLists目錄通用模板Win&Linux相容動態編寫

CMakeLists多目錄通用模板 CMake不僅具有跨平臺(一次編寫,多次編譯)的特點,還有便於工程管理的特點,支援CMake的IDE也有很多(VS[MS],QT,CodeBlock等)。 以一個通用組織的工程(包含PCL,VTK,libLAS第三方庫)為

[Makefile]目錄Makefile寫法

16px 間隔 ews pro images include 先來 文章 status 最近需要寫一個測試程序,這個測試程序需要集成一些功能,寫在同一個文件看上去很不好,多個文件的Makefile又不是很熟,於是分享下面這篇文章 轉自:http://blog.csdn.ne

執行緒實現檔案在目錄中查詢拷貝到目錄

在實現建立多級目錄後,遇到了檔案分類複製的問題。。。左思右想,最後覺得還是寫程式碼實現比較快,畢竟我比較懶。。。不要問我為要寫那麼多find方法來匹配路徑。。。畢竟腦子不夠用。如果是比較重要的檔案,不推薦多執行緒去實現,雖然用了同步,但還是有可能漏掉某個檔案。還是老老實實的

批量更新和打包個Git目錄

# 批量更新多個Git庫建立一個專門存放git庫專案的目錄,例如D:\git。project專案的本地git庫目錄為D:\git\project\.git。更新(git pull)D:\git目錄下的所有Git/Hg專案,在該目錄下執行gitpullall.bat批處理檔案:

檔案編譯的makefile編寫(附當前目錄下所有.c/.cpp檔案編譯makefile)

C程式碼是如何變成可以執行程式的過程:     1、由前處理器把程式設計師所編寫的C程式碼翻譯成標準C程式碼,可以得到以.i結尾的預處理檔案。         gcc -E code.c         gcc -E code.c -o code.i      2、由彙編器

linuxSVN版本同步檔案到WEB目錄

svn hooks位置一定要確定,即你的 版本庫位置,配置hooks更新到對應的網站目錄。 一 安裝與配置SVN 1.安裝subversion centos: yum install subversion ubuntu: apt-get install subv

包含目錄目錄、附加包含目錄、附加目錄、附加依賴項如何使用? 靜態,動態的建立與呼叫和vs裡引用的使用

引言:vs中怎麼新增外部標頭檔案?如過直接在專案標頭檔案處,新增一下,如下圖:則,依然會報錯,如下圖:有兩種方法,來解決(你不在vs上的新增它也沒事):(1) 直接把外部標頭檔案複製過來,放在此專案下即與該專案cpp檔案同一目錄,如下圖:(2)專案右鍵,屬性裡的C/C++ 

包含目錄目錄、附加包含目錄、附加目錄、附加依賴項如何使用? 靜態,動態的創建與調用和vs裏引用的使用

pragma 經驗 dll blog res 編譯器 rdquo 編譯期 靜態 https://blog.csdn.net/Young__Fan/article/details/80528740 引言:vs中怎麽添加外部頭文件?如過直接在項目頭文件處,添加一下,如下

sql server 2008 r2 無法定位到數據文件目錄

src logs 子目錄 數據 屬性 添加 文件目錄 無法定位 ges 像這樣,選擇數據庫文件時, 無法定位到文件夾目錄,子目錄下的都不顯示。明明選擇的這個文件夾裏還有很多子文件夾,卻顯示不了。 解決方法: 在此文件夾上右擊,屬性-安全 添加紅框中的用戶就可以

python2.7.13標準文件目錄操作與文件操作

mov abs 庫文件 shell htm .com 及其 rec lose 標準庫的中文參考文檔: http://python.usyiyi.cn/translate/python_278/library/index.html 官方標準庫文檔:https://docs.p

MYSQL Data目錄查找如何遷移

sed 數據庫 and settings cat documents 復制 找到 ria MySQL數據庫安裝成功後,卻發現在MySQL安裝目錄下的Data目錄竟然沒有新建的數據庫?那麽如何查找真正的data目錄呢?下面3A網絡小錢今天就來教你如何查找真正的Data目錄並遷

subversion版本導入導出相關遷移

svn subversion visualsvn subversion在實際項目研發中被大量的應用,但是往往在實際的環境中大多數的人還僅僅把SVN僅用於創建一個SVN庫,當然在subversion也是支持一個SVN服務多個版本庫的,最近剛剛好在做SVN的跨系統平臺遷移工作,就此就簡單的說一說

NFS共享目錄,掛載應用

nfs 服務 掛載 共享目錄 (1) nfs server導出/data/application/web,在目錄中提供wordpress; (2) nfs client掛載nfs server導出的文件系統至/var/www/html; (3) 客戶端(lamp),部署wordpress,並讓其正常訪問;要

HTML相對路徑相對目錄--上級目錄下級目錄的寫法

ref wro 文件 pre -- 所在 表示 wow 文件的 如何表示上級目錄 ../表示源文件所在目錄的上一級目錄,../../表示源文件所在目錄的上上級目錄,以此類推。 假設info.html路徑是:c:/Inetpub/wwwroot/sites/blabla/in

Linux各目錄每個目錄的詳細介紹

直接 系統引導 ilo 硬盤驅動 另有 升級 針對 更新 pool Linux各目錄及每個目錄的詳細介紹,包括linux常見核心目錄諸如/bin,/etc,/home,/usr,/root,/dev,/var,/proc等常見目錄詳細介紹及說明。 linux常見目錄說明 /

文件Linux目錄結構

module 最好 win 對待 行修改 fstab size idc .html 什麽是文件 在linux系統上,所有的資源都是文件,Linux系統下的文件類型包括 普通文件(-) 目錄(d) 符號鏈接(l) 字符設備文件(c) 塊設備文件(b) 套接字(s) 命令管道

C#獲取IIS所有站點虛擬目錄和應用程序(包含名稱詳細信息)

local ren localhost rem ace rms 獲取 set 目錄 原文出處:傳送門 using System; using System.Collections.Generic; using System.ComponentModel; using Sy