Makefile:将对象编译为源文件夹

时间:2014-11-27 00:30:59

标签: c makefile

我有以下makefile

# project name (generate executable with this name)
TARGET   = tp3

CC       = gcc -std=c99 -c
# compiling flags here
CFLAGS   = -Wall -I. -Werror-implicit-function-declaration

LINKER   = gcc -o
# linking flags here
LFLAGS   = -Wall

# debug flags here
DFLAGS   = -g -DDEBUG

SOURCES  := $(shell find . -type f -name '*.c')
INCLUDES  := $(shell find . -type f -name '*.h')
OBJECTS  := $(SOURCES:.c=.o)
rm       = rm -rf

$(TARGET): obj
    @$(LINKER) $(TARGET) $(LFLAGS) $(OBJECTS)
    @echo "Linking complete!"

obj: $(SOURCES) $(INCLUDES)
    @$(CC) $(CFLAGS) -DNDEBUG $(SOURCES)
    @echo "Compilation complete!"

#debug:
#   gcc $(DFLAGS) $(SOURCES) -o $(TARGET)   

dobj: $(SOURCES) $(INCLUDES)
    @$(CC) $(CFLAGS) $(DFLAGS) $(SOURCES)
    @echo "dlinking complete!"

debug: dobj
    @$(LINKER) $(TARGET) $(LFLAGS) $(DFLAGS) $(OBJECTS) -o $(TARGET)
    @echo "dcompilation complete!"

run:
    ./tp3

clean:
    @$(rm) $(TARGET) $(OBJECTS) *.dSYM
    @echo "Cleanup complete!"

问题是:我在文件夹CMM / CMM中有文件,而OBJECTS假定对象也在CMM / CMM文件夹中,但编译器将它们放在根文件夹中。如何让编译器在CMM / CMM中编译.o文件或告诉模式替换器OBJECTS := $(SOURCES:.c=.o)所有内容都在根文件夹中?

3 个答案:

答案 0 :(得分:3)

这里真正的问题是,您没有使用工具make可以简化您的任务 此外,您的编译器将所有.o文件放在根文件夹中,因为您没有告诉他不要这样做,或者让make为您执行此操作。

这是工作的Makefile:

EXE :=  tp3
SRC :=  $(shell find . -type f -name '*.c')
OBJ :=  $(SRC:.c=.o)

# Preprocessor flags here
CPPFLAGS    :=  -I.
# Compiler flags here
CFLAGS      :=  -std=c99 -Wall -Werror-implicit-function-declaration

.PHONY: all debug run clean

all: CPPFLAGS += -DNDEBUG
all: $(EXE)

debug: CPPFLAGS += -DDEBUG
debug: CFLAGS += -g
debug: $(EXE)

$(EXE): $(OBJ)
    @echo "Compilation complete!"
    $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
    @echo "Linking complete!"

run:
    ./$(EXE)

clean:
    @$(RM) $(EXE) $(OBJ) *.dSYM
    @echo "Cleanup complete!"

Make有一组内置的变量和规则,你应该使用这些变量和规则来避免浪费时间和遇到简单的错误。

请注意,此Makefile不能很好地处理依赖项,只需将.h文件列表添加到Makefile就不够了。您可以通过让编译器动态创建依赖项文件以及.o文件的编译来解决此问题:

  • 构建.d文件名列表:DEP := $(OBJ:.o=.d)
  • 告诉编译器生成相应的文件,将-MMD -MP开关添加到CPPFLAGS内置变量
  • 将它们包含在Makefile中,以便解析其内容:-include $(DEP)
  • 请勿忘记清理它们,将$(DEP)添加到$(RM)目标中的clean命令。

结果:

EXE :=  tp3
SRC :=  $(shell find . -type f -name '*.c')
OBJ :=  $(SRC:.c=.o)
DEP :=  $(OBJ:.o=.d)

# Preprocessor flags here
CPPFLAGS    :=  -MMD -MP -I.
# Compiler flags here
CFLAGS      :=  -std=c99 -Wall -Werror-implicit-function-declaration

.PHONY: all debug run clean

all: CPPFLAGS += -DNDEBUG
all: $(EXE)

debug: CPPFLAGS += -DDEBUG
debug: CFLAGS += -g
debug: $(EXE)

$(EXE): $(OBJ)
    @echo "Compilation complete!"
    $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
    @echo "Linking complete!"

-include $(DEP)

run:
    ./$(EXE)

clean:
    @$(RM) $(EXE) $(OBJ) $(DEP) *.dSYM
    @echo "Cleanup complete!"

如果您有任何疑问,请继续。

答案 1 :(得分:1)

如果你使用GNU make,那么你可以使用patters rules甚至static patterns

%.o: %.c
        $(CC) -c $(CFLAGS) $< -o $@

如果没有,请使用旧语法

.c.o:

答案 2 :(得分:-1)

here are the contents of two makefile items.
 a top level makefile the drives the makefile.bot
the makefile.bot handles files/executables in other directorys
these makefiles also use recursion to produce the dependency lists
so only those header files that are actually include'd in the source
are listed as dependencies for that source.
Note: there are several common .c and .h files in the top level directory
      so they are compiled first, then referenced later
      when performing the link activity in each of the sub directories
Note: the 'AllDirectorys' is a list of the sub directories 
      where source code is to be compiled/linked in individual executables
Note: this is setup to run on Linux, and uses linux shell commands
      and certain utilities, like 'sed'

file: makefile.mak (the top level file)

    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 -W

#CPPFLAGS += =MD

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



.PHONY: AllDirectories
# the following statement needs to be edited as
# subdirectories are added/deleted/re-named
AllDirectories := \
    CommandConfiguration \
    Communication \
    MainScheduler \
    RetrieveCDSLog \
    RetrieveEventRecorderLog \
    RetrieveGPS \
    QESRouter



#AllDirectories :=  \
#    MainScheduler \
#    Communication  \
#    RetrieveGPS   \
#    TestCommunicationDev



.PHONY: all
#all: $(OBJ) $(AllDirectories)
#   $(foreach d,$(AllDirectories), \
#    ( cd $d && $(MAKE) -f makefile.mak name=Tsk_$d 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


file: makefile.bot  which only occurs once, in the top level directory
along side the above listed makefile.mak

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 -f

MV      := mv

LDFLAGS :=  -L/usr/local/lib

DEBUG   :=  -ggdb3

CCFLAGS :=  $(DEBUG) -Wall -W

#CPPFLAGS += =MD

#LIBS    :=  -lidn -lssl -ldl -lrt -lz -lc -lm
LIBS    :=   -lssl -ldl -lrt -lz -lc -lm -lcrypto



#
# 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 =========
    $(CP) $(name) $(BINDIR)/
    # ======= $(name) Copy Done ==========
    #



#
#create dependancy files -- inference rule
#
%.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