多目录工程的makefile示例

本文来源于:http://www.360doc.com/content/12/0403/08/1317564_200410720.shtml转载请注明出处


本文代码虽简单,但涉及比较复杂的各种调用关系,欲研究者需有耐心及清醒头脑。 切切!背景交待:

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]

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-14 16:15:43

多目录工程的makefile示例的相关文章

makefile示例

#定义编译选项CXX = g++ #设置“CXXFLAGS”环境变量CXXFLAGS = -g -Wall -O0 -std=c++0x #定义头文件目录,链接库目录,链接文件INCLUDE_PATH = ../frame/3rdInc/eluna/ ../frame/3rdInc/glog ../frame/3rdInc/google ../frame/3rdInc/json / ../frame/3rdInc/uuid LIB_PATH = ../frame/3rdLibs32/ ../fr

当前工程读取配置文件示例

当前工程目录读取配置示例: public static void main(String[] args) { // TODO Auto-generated method stub System.out.println(getConfigPath()); } public static String getConfigDir(){ String userDir=System.getProperty("user.dir"); if(System.getProperty("os.n

大型工程多个目录下的Makefile写法

1.前言 目前从事于linux下程序开发,涉及到多个文件,多个目录,这时候编译文件的任务量比较大,需要写Makefile.关于Makefile的详细内容可以参考网上流传非常广泛的<跟我一起写Makefile>http://blog.csdn.net/haoel/article/details/2886/,作者是个大牛,非常佩服. 2.简单测试 测试程序在同一个文件中,共有func.h.func.c.main.c三个文件,Makefile写法如下所示: 1 CC = gcc 2 CFLAGS =

一个简单的makefile示例

下面的程序从 Linux 程序设计第四版 引用 文件目录 2.c #include "a.h"#include "b.h"void function_two(){} 3.c #include "b.h"#include "c.h"void function_three(){} main.c #include<stdio.h>#include "a.h"extern void function_t

makefile 示例1

# 设置编译器CC = g++ # -fPIC 作用于编译阶段,告诉编译器产生与位置无关代码# -D宏定义,相当于C中的全局#define,可以通过宏定义来控制源程序的编译,例如:# #ifdef _FILELINE# printf("Hello Yu Qiang, How are you?\n");# #else# printf("Sorry to lost you. \n");# #endif# 程序最终调用输出是: Hello Yu Qiang, How ar

cmake--多级目录工程

前言 很多大工程由不同动态库和程序构成,并表现为多级目录和子工程的样式. 一, 目录结构 ├── CMakeLists.txt  -------------------->[1]├── subbinary│           ├── CMakeLists.txt----------->[2]│           └── main.cpp├── sublibrary1│           ├── CMakeLists.txt------------>[3]│           ├─

为一个工程创建Makefile

一:自动生成Makefile 1. 创建目录,生成一个hello.c 2. 执行 autoscan 命令,生成configure.in模版文件 configure.scan 3. 编辑configure.in文件 AC_PREREQ 版本号 AC_INIT 可执行文件 AM_INIT_AUTOMAKE  指示可执行文件与版本号 AC_CONFIG_SRCDIR  检验文件是否缺失 AC_CONFIG_HEADERS  为了检查头文件config.h AC_PROG_CC  检查C语言编译程序是否

gcc链接g++编译生成的静态库和动态库的makefile示例

使用c++开发程序或者库时,将库提供给其他人使用. 然而使用者是使用c开发的程序,链接g++编译生成的库时,于链接gcc生成的库,有所不同. 首先是静态库,以链接g++编译生成的libmylib.a为例子 mylib依赖于pthread,rt,math库,链接时必须放在mylib之后. 同时-Wl,--no-as-needed -ldl添加在末尾是必须的. arm和x86有些不同,就是arm的gcc不会自动链接数学库math,需要手动添加链接. 1 CC=arm-linux-gnueabihf-

【嵌入式开发】 嵌入式开发工具简介 (裸板调试示例 | 交叉工具链 | Makefile | 链接器脚本 | eclipse JLink 调试环境)

作者 : 韩曙亮 博客地址 : http://blog.csdn.net/shulianghan/article/details/42239705  参考博客 : [嵌入式开发]嵌入式 开发环境 (远程登录 | 文件共享 | NFS TFTP 服务器 | 串口连接 | Win8.1 + RedHat Enterprise 6.3 + Vmware11) 开发环境 : -- 操作系统 : Vmware11 + RedHat6.3 企业版 + Win8.1; -- 硬件 : OK-6410-A 开发