C源文件的Makefile

时间:2021-07-14 22:21:22

Need help in writing a Makefile for below source tree. I have tried out simple examples for Makefile and those worked fine. But not able to figure out how do I write a Makefile for below kind of source tree.

在为源代码树编写Makefile时需要帮助。我已经尝试了Makefile的简单示例,但这些工作正常。但是无法弄清楚如何为下面的源树编写Makefile。

I am organizing my code as below

我正在组织我的代码如下

root_dir:

    Makefile

    component1:
        dir1:
            file1.c file1.h 
        dir2:
            file2.c file2.h
        dir3:
            file3.c file3.h

    component2:
        dir4:
            file4.c file4.h
        dir5:
            file5.c file5.h

    common:
        debug.c debug.h
        utils.c utils.h
        main.c main.h

Here, main.c uses some functions declared in debug.h, utils.h, file1.h and file4.h. These file1.c and file4.c use the debug.h and utils.h. I have started writing the Makefile rules as below.

这里,main.c使用在debug.h,utils.h,file1.h和file4.h中声明的一些函数。这些file1.c和file4.c使用debug.h和utils.h。我已经开始编写Makefile规则,如下所示。

CC=gcc
CFlags=-c -g3 -Wall

myexec: main.o
        $(CC) main.o -o myexec

main.o: common/main.c common/main.h common/utils.h
        $(CC) $(CFLAGS) common/main.c

This Makefile gives "undefined reference" error messages for the functions declared in utils.h. It can crib about the functions declared in debug.h, file1.h or file4.h, but shouldn't have given the error message for functions from utils.h

此Makefile为utils.h中声明的函数提供“未定义的引用”错误消息。它可以解决在debug.h,file1.h或file4.h中声明的函数,但不应该为utils.h中的函数提供错误消息

Please help me in finding out what is wrong with the Makefile here.

请帮我找出Makefile的错误。

2 个解决方案

#1


2  

First let's fix the main.o rule:

首先让我们修复main.o规则:

main.o: common/main.c common/main.h common/utils.h
    $(CC) $(CFLAGS) common/main.c

If, as you say main.c uses some functions declared in debug.h, utils.h, file1.h and file4.h, then those headers should be prerequisites of the rule (so that if you modify a header, Make will rebuild main.o):

如果你说main.c使用在debug.h,utils.h,file1.h和file4.h中声明的一些函数,那么这些头应该是规则的先决条件(这样如果你修改一个头,Make将重建main.o),此:

main.o: common/main.c common/main.h common/debug.h common/utils.h component1/dir1/file1.h component2/dir4/file4.h
    $(CC) $(CFLAGS) common/main.c

Now look at the myexec rule:

现在看看myexec规则:

myexec: main.o
    $(CC) main.o -o myexec

It's no surprise that you get "undefined reference" errors; the functions declared in debug.h, utils.h, file1.h and file4.h are defined in (I presume) debug.c, utils.c, file1.c and file4.c, which this makefile never mentions. Do not proceed until you understand this.

你得到“未定义的引用”错误就不足为奇了;在debug.h,utils.h,file1.h和file4.h中声明的函数在(我推测)debug.c,utils.c,file1.c和file4.c中定义,这个makefile从未提及过。在你明白这一点之前不要继续。

The way to handle this is tho have the myexec rule link all of the relevant object files:

处理这个的方法是让myexec规则链接所有相关的目标文件:

myexec: main.o debug.o utils.o file1.o file4.o
    $(CC) main.o debug.o utils.o file1.o file4.o -o myexec

Naturally you must have rules for debug.o, utils.o, file1.o and file4.o, similar to the one for main.o.

当然,你必须有debug.o,utils.o,file1.o和file4.o的规则,类似于main.o的规则。

Once that is done, you have a makefile that works but is needlessly long and redundant. "Effective but crude". It can be made much shorter and more elegant, but this answer is getting long; just get it working, then we can work on making it cleaner.

一旦完成,你就有了一个可以工作的makefile,但是不必要地冗长冗余。 “有效但粗糙”。它可以做得更短更优雅,但这个答案越来越长;只是让它工作,然后我们可以努力使其更清洁。

#2


0  

here is a long example: it is for a linux embedded system, but will work with only minor changes for your application

这是一个很长的例子:它适用于Linux嵌入式系统,但只对您的应用程序进行微小的更改

These two makefiles will create an executable in each sub directory

这两个makefile将在每个子目录中创建一个可执行文件

it has a directory tree something like the following:

它有一个类似于以下目录树:

top
    utility .h and .c files
    makefile.top
    makefile.bot
    /executable1
        exec1 .h and .c files
    /executable2
        exec2 .h and .c files

contents of makefile.mak

makefile.mak的内容

SHELL = /bin/sh


#  note: this makefile.mak needs to be run from the ./src directory
# of the GOT4 directory tree


SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)


MAKE    :=  /usr/bin/make

CC      :=  /usr/bin/gcc

CP      :=  cp

MV      :=  mv

LDFLAGS :=  -L/usr/local/lib -L/usr/lib -L/lib

DEBUG   :=  -ggdb3

CCFLAGS :=  $(DEBUG) -Wall -Wextra -pedantic

#CPPFLAGS += =MD

LIBS    :=  -lssl -ldl -lrt -lz -lc -lm



.PHONY: AllDirectories


AllDirectories :=  \
    executable1 \
    executable2 



.PHONY: all

all: $(OBJ) $(AllDirectories)
    $(foreach d,$(AllDirectories), \
    ( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d all ); )



#
# create dependancy files
#
%.d: %.c
    # 
    # ========= START $< TO $@ =========
    $(CC) -M $(CPPFLAGS) $< > $@.$$$$;                      \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@;     \
    rm -f $@.$$$$
    # ========= END $< TO $@ =========



#
# compile the .c file into .o files using the compiler flags
#
%.o: %.c %.d 
    # 
    # ========= START $< TO $@ =========
    $(CC) $(CCFLAGS) -c $< -o $@ -I. 
    # ========= END $< TO $@ =========
    # 



.PHONY: clean
#clean: $(AllDirectories)
#   # ========== start clean activities ==========
#   rm -f *.o
#   rm -f $(name).map
#   rm -f $(name)
#   rm -f *.d
#   $(foreach d,$(AllDirectories), \
#    ( cd $d && $(MAKE) -f makefile.mak clean ); )
#   # ========== end clean activities ==========

clean: $(AllDirectories)
    # ========== start clean activities ==========
    rm -f *.o
    rm -f $(name).map
    rm -f $(name)
    rm -f *.d
    rm -f ../bin/Tsk_*
    $(foreach d,$(AllDirectories), \
    ( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d clean ); )
    # ========== end clean activities ==========



.PHONY: install
#install: $(AllDirectories)
#   # ========== start install activities ==========
#   $(foreach d,$(AllDirectories), \
#    ( cd $d && $(MAKE) -f makefile.mak clean ); )
#   # ========== end install activities ==========

install: $(AllDirectories)
    # ========== start install activities ==========
    $(foreach d,$(AllDirectories), \
    ( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d install ); )
    # ========== end install activities ==========



# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that file 
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif

and the makefile.bot

和makefile.bot

SHELL = /bin/sh


BINDIR  :=  /home/user/bin


.PHONY: all
all : $(BINDIR)/$(name) ../makefile.mak ../makefile.bot


#
# macro of all *.c files 
# (NOTE:
# (the following 'wildcard' will pick up ALL .c files
# (like FileHeader.c and FunctionHeader.c 
# (which should not be part of the build
# (so be sure no unwanted .c files in directory
# (or change the extension
#
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)


COMMON_OBJ := $(wildcard ../*.o)
#COMMON_SRC := $(wildcard ../*.c)
#COMMON_OBJ := $(COMMON_SRC:.c=.o)
#COMMON_DEP := $(COMMON_SRC:.c=.d)
#COMMON_INC := $(COMMON_SRC:.c=.h)

MAKE    :=  /usr/bin/make

CC      :=  /usr/bin/gcc

CP      :=  cp

MV      := mv

LDFLAGS :=  -L/usr/local/lib

DEBUG   :=  -ggdb3

CCFLAGS :=  $(DEBUG) -Wall -Wextra -pedantic -std=c99

#CPPFLAGS += =MD

LIBS    :=   -lssl -ldl -lrt -lz -lc -lm



#
# link the .o files into the executable 
# using the linker flags
# -- explicit rule
#
$(name): $(OBJ) $(COMMON_OBJ) ../makefile.mak ../makefile.bot
    #
    # ======= $(name) Link Start =========
    $(CC) $(LDFLAGS) -o $@ $(OBJ) $(COMMON_OBJ) $(LIBS)
    # ======= $(name) Link Done ==========
    #



# note:
# using MV rather than CP results in all executables being re-made everytime
$(BINDIR)/$(name): $(name)
    #
    # ======= $(name) Copy Start =========
    sudo $(CP) $(name) $(BINDIR)/.
    # ======= $(name) Copy Done ==========
    #



#
#create dependancy files -- inference rule
# list makefile.mak as dependancy so changing makfile forces rebuild
#
%.d: %.c 
    # 
    # ========= START $< TO $@ =========
    $(CC) -M $(CPPFLAGS) $< > $@.$$$$;                      \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@;     \
    rm -f $@.$$$$
    # ========= END $< TO $@ =========



# 
# compile the .c file into .o files using the compiler flags
# -- inference rule
#
%.o: %.c %.d 
    # 
    # ========= START $< TO $@ =========
    $(CC) $(CCFLAGS) -c $< -o $@ -I. 
    # ========= END $< TO $@ =========
    # 



.PHONY: clean
clean: 
    # ========== CLEANING UP ==========
    rm -f *.o
    rm -f $(name).map
    rm -f $(name)
    rm -f *.d
    # ========== DONE ==========



.PHONY: install
install: all

# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that .c file 
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif

#1


2  

First let's fix the main.o rule:

首先让我们修复main.o规则:

main.o: common/main.c common/main.h common/utils.h
    $(CC) $(CFLAGS) common/main.c

If, as you say main.c uses some functions declared in debug.h, utils.h, file1.h and file4.h, then those headers should be prerequisites of the rule (so that if you modify a header, Make will rebuild main.o):

如果你说main.c使用在debug.h,utils.h,file1.h和file4.h中声明的一些函数,那么这些头应该是规则的先决条件(这样如果你修改一个头,Make将重建main.o),此:

main.o: common/main.c common/main.h common/debug.h common/utils.h component1/dir1/file1.h component2/dir4/file4.h
    $(CC) $(CFLAGS) common/main.c

Now look at the myexec rule:

现在看看myexec规则:

myexec: main.o
    $(CC) main.o -o myexec

It's no surprise that you get "undefined reference" errors; the functions declared in debug.h, utils.h, file1.h and file4.h are defined in (I presume) debug.c, utils.c, file1.c and file4.c, which this makefile never mentions. Do not proceed until you understand this.

你得到“未定义的引用”错误就不足为奇了;在debug.h,utils.h,file1.h和file4.h中声明的函数在(我推测)debug.c,utils.c,file1.c和file4.c中定义,这个makefile从未提及过。在你明白这一点之前不要继续。

The way to handle this is tho have the myexec rule link all of the relevant object files:

处理这个的方法是让myexec规则链接所有相关的目标文件:

myexec: main.o debug.o utils.o file1.o file4.o
    $(CC) main.o debug.o utils.o file1.o file4.o -o myexec

Naturally you must have rules for debug.o, utils.o, file1.o and file4.o, similar to the one for main.o.

当然,你必须有debug.o,utils.o,file1.o和file4.o的规则,类似于main.o的规则。

Once that is done, you have a makefile that works but is needlessly long and redundant. "Effective but crude". It can be made much shorter and more elegant, but this answer is getting long; just get it working, then we can work on making it cleaner.

一旦完成,你就有了一个可以工作的makefile,但是不必要地冗长冗余。 “有效但粗糙”。它可以做得更短更优雅,但这个答案越来越长;只是让它工作,然后我们可以努力使其更清洁。

#2


0  

here is a long example: it is for a linux embedded system, but will work with only minor changes for your application

这是一个很长的例子:它适用于Linux嵌入式系统,但只对您的应用程序进行微小的更改

These two makefiles will create an executable in each sub directory

这两个makefile将在每个子目录中创建一个可执行文件

it has a directory tree something like the following:

它有一个类似于以下目录树:

top
    utility .h and .c files
    makefile.top
    makefile.bot
    /executable1
        exec1 .h and .c files
    /executable2
        exec2 .h and .c files

contents of makefile.mak

makefile.mak的内容

SHELL = /bin/sh


#  note: this makefile.mak needs to be run from the ./src directory
# of the GOT4 directory tree


SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)


MAKE    :=  /usr/bin/make

CC      :=  /usr/bin/gcc

CP      :=  cp

MV      :=  mv

LDFLAGS :=  -L/usr/local/lib -L/usr/lib -L/lib

DEBUG   :=  -ggdb3

CCFLAGS :=  $(DEBUG) -Wall -Wextra -pedantic

#CPPFLAGS += =MD

LIBS    :=  -lssl -ldl -lrt -lz -lc -lm



.PHONY: AllDirectories


AllDirectories :=  \
    executable1 \
    executable2 



.PHONY: all

all: $(OBJ) $(AllDirectories)
    $(foreach d,$(AllDirectories), \
    ( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d all ); )



#
# create dependancy files
#
%.d: %.c
    # 
    # ========= START $< TO $@ =========
    $(CC) -M $(CPPFLAGS) $< > $@.$$$$;                      \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@;     \
    rm -f $@.$$$$
    # ========= END $< TO $@ =========



#
# compile the .c file into .o files using the compiler flags
#
%.o: %.c %.d 
    # 
    # ========= START $< TO $@ =========
    $(CC) $(CCFLAGS) -c $< -o $@ -I. 
    # ========= END $< TO $@ =========
    # 



.PHONY: clean
#clean: $(AllDirectories)
#   # ========== start clean activities ==========
#   rm -f *.o
#   rm -f $(name).map
#   rm -f $(name)
#   rm -f *.d
#   $(foreach d,$(AllDirectories), \
#    ( cd $d && $(MAKE) -f makefile.mak clean ); )
#   # ========== end clean activities ==========

clean: $(AllDirectories)
    # ========== start clean activities ==========
    rm -f *.o
    rm -f $(name).map
    rm -f $(name)
    rm -f *.d
    rm -f ../bin/Tsk_*
    $(foreach d,$(AllDirectories), \
    ( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d clean ); )
    # ========== end clean activities ==========



.PHONY: install
#install: $(AllDirectories)
#   # ========== start install activities ==========
#   $(foreach d,$(AllDirectories), \
#    ( cd $d && $(MAKE) -f makefile.mak clean ); )
#   # ========== end install activities ==========

install: $(AllDirectories)
    # ========== start install activities ==========
    $(foreach d,$(AllDirectories), \
    ( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d install ); )
    # ========== end install activities ==========



# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that file 
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif

and the makefile.bot

和makefile.bot

SHELL = /bin/sh


BINDIR  :=  /home/user/bin


.PHONY: all
all : $(BINDIR)/$(name) ../makefile.mak ../makefile.bot


#
# macro of all *.c files 
# (NOTE:
# (the following 'wildcard' will pick up ALL .c files
# (like FileHeader.c and FunctionHeader.c 
# (which should not be part of the build
# (so be sure no unwanted .c files in directory
# (or change the extension
#
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)


COMMON_OBJ := $(wildcard ../*.o)
#COMMON_SRC := $(wildcard ../*.c)
#COMMON_OBJ := $(COMMON_SRC:.c=.o)
#COMMON_DEP := $(COMMON_SRC:.c=.d)
#COMMON_INC := $(COMMON_SRC:.c=.h)

MAKE    :=  /usr/bin/make

CC      :=  /usr/bin/gcc

CP      :=  cp

MV      := mv

LDFLAGS :=  -L/usr/local/lib

DEBUG   :=  -ggdb3

CCFLAGS :=  $(DEBUG) -Wall -Wextra -pedantic -std=c99

#CPPFLAGS += =MD

LIBS    :=   -lssl -ldl -lrt -lz -lc -lm



#
# link the .o files into the executable 
# using the linker flags
# -- explicit rule
#
$(name): $(OBJ) $(COMMON_OBJ) ../makefile.mak ../makefile.bot
    #
    # ======= $(name) Link Start =========
    $(CC) $(LDFLAGS) -o $@ $(OBJ) $(COMMON_OBJ) $(LIBS)
    # ======= $(name) Link Done ==========
    #



# note:
# using MV rather than CP results in all executables being re-made everytime
$(BINDIR)/$(name): $(name)
    #
    # ======= $(name) Copy Start =========
    sudo $(CP) $(name) $(BINDIR)/.
    # ======= $(name) Copy Done ==========
    #



#
#create dependancy files -- inference rule
# list makefile.mak as dependancy so changing makfile forces rebuild
#
%.d: %.c 
    # 
    # ========= START $< TO $@ =========
    $(CC) -M $(CPPFLAGS) $< > $@.$$$$;                      \
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@;     \
    rm -f $@.$$$$
    # ========= END $< TO $@ =========



# 
# compile the .c file into .o files using the compiler flags
# -- inference rule
#
%.o: %.c %.d 
    # 
    # ========= START $< TO $@ =========
    $(CC) $(CCFLAGS) -c $< -o $@ -I. 
    # ========= END $< TO $@ =========
    # 



.PHONY: clean
clean: 
    # ========== CLEANING UP ==========
    rm -f *.o
    rm -f $(name).map
    rm -f $(name)
    rm -f *.d
    # ========== DONE ==========



.PHONY: install
install: all

# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that .c file 
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif