【问题标题】:make for compiling — all *.c files in folders & subfolders in projectmake 用于编译 - 项目中文件夹和子文件夹中的所有 *.c 文件
【发布时间】:2013-10-23 10:40:28
【问题描述】:

为了编译两个文件,我创建了一个 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 调用该 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();

两个.c 内容:---

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

#include "two.h"

void two()
{

  printf("\n two \n");

}

两个.h内容:---

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$ 

【问题讨论】:

标签: linux makefile


【解决方案1】:

广告 1 和 2:文件名可以安全地包含目录,% 可以根据需要匹配 /。所以你可以轻松拥有:

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

甚至

$(wildcard */*.c)

... 或者按照 keltar 在评论中的建议

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

这是递归的。

广告 3:你正在做。

广告4:创建一个以$(OBJ)为依赖的目标,并像编译一样使用自动变量:

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

【讨论】:

  • $(shell find . -name '*.c')
  • 感谢您的回复 --- OBJ := $(patsubst %.c,%.o,$(wildcard /.c)) -- 如果我更改 OBJ按照您的建议,它将从当前目录和子目录中搜索..? .. 此外,每个文件的 *.o 都将在各自的文件夹或主文件夹中创建?
  • 还有一个问题 --- 在这种情况下,我的干净目标收据是否正确?
  • @Katoch: $(wildcard */*.c) 只会在直接子目录中搜索。 * 从不匹配 /。如果你想搜索任何深度,你需要$(shell find . -name '*.c')
  • @Katoch:当然 clean 中的模式需要与用于生成源列表的模式相匹配。可以只做rm -f $(OBJ)(它永远不会-r,参数始终是文件,而不是目录),但是如果你删除一个源,之后对象将不会被清理。因此,具有匹配模式有一些优势。对于$(shell find . -name '*.c'),匹配命令是find . -name '*.o' | xargs rm(在前一种情况下您需要-f,因为您传递的名称不存在;在不存在的情况下您不需要它)。
【解决方案2】:

也许还有另一种解决方案。我的项目目录中有一个源目录,其中包含子目录。而且我不想在每个子目录或其他东西中都有一个 Makefile。而且我只想在项目的rootdir中使用一个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 实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-01
    • 1970-01-01
    相关资源
    最近更新 更多