在项目中,将文件夹及其子文件夹中的所有*.c文件编译的方法是什么?

6
为编译两个文件,我创建了一个makefile,在其中使用对象名称或者可以使用patsubst模式规则来说明。
# ----------------------------------------------------------------------------
# Makefile for building tapp
#
# Copyright 2010 FriendlyARM (http://www.arm9.net/)
#

ifndef DESTDIR
DESTDIR            ?= /opt/FriendlyARM/tiny6410/linux/rootfs_qtopia_qt4
endif

#CFLAGS              = -c -Wall -O2  # wall is for warning show and 02 is optiminisation level 2
CFLAGS              = -c -O2  # wall is for warning show and 02 is optiminisation level 2
#CC                    = arm-linux-gcc   # compiler name
CC                    = gcc   # compiler name
LD                    = ld

INSTALL             = install         # 

TARGET              = led_player_project

#OBJ = led-player_backup.o led-player.o
OBJ := $(patsubst %.c,%.o,$(wildcard *.c */*.c))

#OBJ = $(shell find . -name '*.c')

all: $(TARGET) 
#all: $(OBJ)

led_player_project : $(OBJ)
    $(LD) $(LDFLAGS) -o $@ $(OBJ) $(LIBS)
#       $(LD) $(LDFLAGS) -o $@ $< $(LIBS)

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

#$< -o $@


install: $(TARGET)
    $(INSTALL) $^ $(DESTDIR)/usr/bin

clean :
    rm -rf *.o $(TARGET) $(OBJ)


# ----------------------------------------------------------------------------

.PHONY: $(PHONY) install clean

# End of file
# vim: syntax=make

#EOF

现在,如果我的项目包含文件夹和子文件夹,而它们又包含更多的文件。那么我是否可以编写模式规则来编译每个文件并创建一个通用可执行文件?
1. 我需要在每个子文件夹中创建makefile,以便我可以从主makefile中调用它,就像将静态驱动程序集成到Linux内核一样,每个驱动程序都有相应的makefile吗? 2. 还是为整个项目创建一个通用makefile? 3. 我能否使用patsubst编译每个文件而无需提及其名称? 4. 如何将每个*.o组合成一个名为“main”的可执行文件?
编辑:--- @Jan Hudec 根据您的评论,我已修改了我的makefile(我已经发布了它)。现在我只是尝试在我的主文件夹内部使用两个文件夹。我得到以下错误 文件夹结构:--
main Folder  ----> one Folder 
             ----> two Folder 

主文件夹包含:--

main.c 
main.h
Makefile

文件夹一包含:--

one.c
one.h

文件夹二包含以下内容:--

two.c
two.h

main.c内容如下:

#include <stdio.h>
#include <stdlib.h>

#include "main.h"

int main()
{
  char *p;

  printf("\n\n main \n");

  one();
  two();

  return 0;
}

main.h 内容:

#include "one/one.h"
#include "two/two.h"

one.c 内容:

    #include <stdio.h>
    #include <stdlib.h>

#include "one.h"

    void one()
    {

      printf("\n one \n");

    }

one.h 内容:

void one();

two.c content :---

#include <stdio.h>
#include <stdlib.h>

#include "two.h"

void two()
{

  printf("\n two \n");

}

two.h content :---

void two();

我在编译时遇到了错误,具体如下:

ignite@ignite:~/testing/main$ make
gcc    -c -O2   main.c -o main.o
gcc    -c -O2   one/one.c -o one/one.o
gcc    -c -O2   two/two.c -o two/two.o
ld  -o led_player_project main.o one/one.o two/two.o 
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080
main.o: In function `main':
main.c:(.text.startup+0x11): undefined reference to `puts'
one/one.o: In function `one':
one.c:(.text+0xb): undefined reference to `puts'
two/two.o: In function `two':
two.c:(.text+0xb): undefined reference to `puts'
make: *** [led_player_project] Error 1
ignite@ignite:~/testing/main$ 

相关内容:https://dev59.com/fXE95IYBdhLWcg3wDpcG - Ciro Santilli OurBigBook.com
2个回答

10

广告1和2:文件名可以安全地包含目录,并且%将根据需要匹配/。因此,您可以轻松创建以下文件:

$(wildcard subdir/*.c) $(wildcard anotherdir/*.c)

甚至更多

$(wildcard */*.c)

...或者根据keltar在评论中的建议

$(shell find . -name '*.c')

这是一个递归的函数。

第三条建议:你正在做它。

第四条建议:创建一个以$(OBJ)为依赖项的目标,并像进行编译一样使用自动变量:

main : $(OBJ)
        $(LD) $(LDFLAGS) -o $@ $< $(LIBS)

2
或者 $(shell find . -name '*.c') - keltar
@Katoch:当然,clean中的模式需要与用于生成源列表的模式匹配。可以只执行rm -f $(OBJ)(永远不是-r,参数始终是文件而不是目录),但如果删除源,则对象将不会被清理。因此,具有匹配模式有一定的优势。对于$(shell find . -name '*.c'),匹配命令是find . -name '*.o' | xargs rm(在前一种情况下需要-f,因为您正在传递不存在的名称;在查找情况下不需要它)。 - Jan Hudec
@JanHudec... 我按照您建议的更改makefile后出现了错误。请看一下我编辑过的上面的帖子。 - Katoch
@Katoch:这与我们迄今讨论的更改无关。您的编译命令只是缺少“-c”标志。 - Jan Hudec
CFLAGS = -c -Wall -O2。因为我们正在编译不同的目标文件,然后将它们组合在一起,所以我们需要-c选项。根据这个链接http://www.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html。另外,我忘了定义$(LD)和ld,对吧? - Katoch
显示剩余5条评论

2
也许还有另一种解决方案。我的项目目录中有一个源目录,其中包含子目录。我不想在每个子目录或其他地方都有一个Makefile。我只想使用项目根目录中的一个Makefile构建所有内容:所以对于我的C ++静态库,我做了这个Makefile。也许这对你也是一个解决方案。但我没有通过“make -j4”等并行构建进行充分测试。
BUILDCXX=g++-10
CHECKCXX=clang++-12

CXXFLAGS=-std=c++17 -Wall -Werror -Wextra -g -pg -O0 -I. -DDEBUG
CXXFLREL=-std=c++17 -Wall -Werror -Wextra -O3 -s -I. -DNDEBUG
CXXFLAGSLIB=$(CXXFLAGS)
CXXFLAGSTST=$(CXXFLAGS) -DRLOG_COMPONENT="clbc"

LDFLAGS=
LDFLAGSLIB=$(LDFLAGS)
LDFLAGSTST=$(LDFLAGS) -L./target/lib -lUnitTest++ -lclbc

OUTDIR=target
OUTDIRLIB=$(OUTDIR)/lib
OUTDIRTST=$(OUTDIR)/bin
OUTDIROBJ=$(OUTDIR)/obj
OUTFILELIB=libclbc.a
OUTFILETST=runtests

SRCDIR=source
SRCDIRLIB=$(SRCDIR)/lib
SRCDIRTST=$(SRCDIR)/test
SRCDIRSLIBR := $(shell find $(SRCDIRLIB) -maxdepth 3 -type d)
SRCFILESLIB := $(foreach dir,$(SRCDIRSLIBR),$(wildcard $(dir)/*.cpp))
OBJFILESLIB := $(addprefix $(OUTDIROBJ)/,$(notdir $(patsubst %.cpp,%.o,$(SRCFILESLIB))))
SRCDIRSTSTR := $(shell find $(SRCDIRTST) -maxdepth 3 -type d)
SRCFILESTST := $(foreach dir,$(SRCDIRSTSTR),$(wildcard $(dir)/*.cpp))
OBJFILESTST := $(addprefix $(OUTDIROBJ)/,$(notdir $(patsubst %.cpp,%.o,$(SRCFILESTST))))


.PHONY: all


all: clean lib


check-syntax:
    $(CHECKCXX) $(CXXFLAGS) -s -o /dev/null -S $(CHK_SOURCES)


clean:
    @rm -rf $(OUTDIR)


lib:$(OBJFILESLIB)
    @mkdir -p $(OUTDIRLIB)
    @echo " TargetLib :" $(OUTDIRLIB)/$(OUTFILELIB) 
    @ ar rcs $(OUTDIRLIB)/$(OUTFILELIB) $^


test:$(OBJFILESTST)
    @mkdir -p $(OUTDIRTST)
    @echo "TargetTest :" $(OUTDIRTST)/$(OUTFILETST)
    @ $(BUILDCXX) $(OBJFILESTST) -o $(OUTDIRTST)/$(OUTFILETST) $(LDFLAGSTST)


release: CXXFLAGSLIB=$(CXXFLREL)
release:$(OBJFILESLIB)   
    @mkdir -p $(OUTDIRLIB)
    @echo "RTargetLib :" $(OUTDIRLIB)/$(OUTFILELIB) 
    @ ar rcs $(OUTDIRLIB)/$(OUTFILELIB) $^


define set_real_src_file
    $(eval REAL_SRC_FILE=$(strip $(1)))
endef

define set_nothing
endef

define get_real_src_file
    $(if $(strip $(findstring $(strip $(1)),$(strip $(2)))),$(call set_real_src_file,$(2)),$(call set_nothing))
endef

define get_source_file
    @echo ObjectFile : $(1)
    $(eval REAL_SRC_SEARCH=$(notdir $(patsubst %.o,%.cpp,$(1))))
    $(eval REAL_SRC_FILE=)
    $(foreach word,$(2), $(call get_real_src_file, $(REAL_SRC_SEARCH),$(word)))
endef


$(OBJFILESLIB): $(SRCFILESLIB)
    @mkdir -p $(OUTDIROBJ)
    $(call get_source_file,$@,$^,$<)
    @ $(BUILDCXX) $(CXXFLAGSLIB) -c $(REAL_SRC_FILE) -o $@


$(OBJFILESTST): $(SRCFILESTST)
    @mkdir -p $(OUTDIROBJ)
    $(call get_source_file,$@,$^,$<)
    @ $(BUILDCXX) $(CXXFLAGSTST) -c $(REAL_SRC_FILE) -o $@

但我猜它只能在GNUMake上运行,无法在其他make实现上运行。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接