【问题标题】:How can I build variants of an executable with one makefile?如何使用一个 makefile 构建可执行文件的变体?
【发布时间】:2011-01-10 21:01:31
【问题描述】:


我有一组源文件,我需要从中生成可执行文件的多个变体。例如,我需要从同一个 ma​​in.c 生成 app1.elfapp2.elfapp3.elf > 和 comm.c。每个应用程序之间的区别在于一个节点地址,一个在 gcc 调用中向下传递的参数。即:

gcc -DNODE=1 -oapp1.elf main.c 
gcc -DNODE=2 -oapp2.elf main.c 
gcc -DNODE=3 -oapp3.elf main.c 

假设我有以下文件:

  • src/main.c
  • src/comm.c

当我这样运行 Makefile 时:

制作所有节点

make 只构建 app1.elf,输出如下:

内置应用程序1
构建应用程序2
内置app3

失败! 输出似乎表明它有效,但它只生成一个可执行文件,即 app1.elf。有人愿意指出我做错了什么吗?

为了进一步解释我的 Makefile,我创建了一个 cleanobjs 目标来清除 ./obj 子目录中的对象。这是我尝试使用新的 node 地址“make”重建 obj 文件,但它失败了。我是否以不打算使用的方式使用“make”?我知道我也可以创建一个批处理文件来运行 make (我已经成功地完成了),但我想知道我做错了什么。我的 Makefile 如下:

obj/%.o: src/%.c
    gcc -DNODE=$(NODE) -o$@ $<

app.elf : ./obj/main.o ./obj/comm.o
    gcc -oapp$(NODE).elf main.o comm.o

node1 : NODE=1
node1 : cleanobj app.elf
    @echo 'Built app1'

node2 : NODE=2
node2 : cleanobj app.elf
    @echo 'Built app2'

node3 : NODE=3
node3 : cleanobj app.elf
    @echo 'Built app3'

all_nodes : node1 node2 node3

cleanobj :
    rm -rf obj/main.o obj/comm.o

.PHONY : cleanobj

【问题讨论】:

  • 只是想补充一点,失败的原因是 make 每个实例只运行一次目标。所以 cleanobj 和 app.elf 都是为 node1 目标构建的,而对于 node2 和 node3 目标,它都被优化了。

标签: c++ c makefile


【解决方案1】:

您将需要针对不同版本的多个目标。每个目标也将需要自己的 main.o 和 comm.o 目标,这意味着您需要将它们称为其他名称,否则它们最终会相互混淆。那么你的所有人都应该发挥作用来构建所有这三个。

【讨论】:

  • 除此之外,您可能还想使用子目录 - 如果您希望您的应用程序的名称完全相同,则必须有一些(其他)方法来区分它们。
  • @foo,该目录是完整文件名的一部分。
  • @AProgrammer 是的,但是目标名称是匹配的。因此,如果您真的想使用相同的目标名称,至少将可执行文件内置到单独的子目录中。
【解决方案2】:

这就是我会做的:

SRC     = src/main.c
OBJ     = $(patsubst src%,obj$(VERSION)%,$(patsubst %.c,%.o,$(SRC)))

C_FLAGS = -DNODE=$(VERSION)


all:    app.1 app.2 app.3

#
# For each application just call make with VERSION set correctly    
app.%:  dir.%
    $(MAKE) VERSION=$* app$*.elf

#
# Build each applications objects into a seprate directory
# So we need to make sure the obj directory exists.    
dir.%:
    @- if ! test -e obj$*; then mkdir obj$*; fi

app%.elf:   $(OBJ)
    $(CC) -o$@ $(C_FLAGS) $(OBJ)


obj$(VERSION)/%.o:  src/%.c
    $(CC) -c -o obj$(VERSION)/$*.o $(C_FLAGS) $<

【讨论】:

  • 成功了!它类似于下面@Achille 发布的解决方案,但这个更通用。我喜欢。谢谢
【解决方案3】:

类似的方法:

ifeq ($(NODE),)

all:
    make NODE=1
    make NODE=2
    make NODE=3

cleanobj:
    make NODE=1 cleanobj
    make NODE=2 cleanobj
    make NODE=3 cleanobj

else

OBJS = main.o comm.o
objs = $(patsubst %.o,obj/$(NODE)/%.o,$(OBJS))

app$(NODE).elf: $(objs)
    gcc -o app$(NODE).elf $^
    @echo 'Built app$(NODE)'

obj/$(NODE)/%.o: src/%.c
    gcc -c -DNODE=$(NODE) -o $@ $<

cleanobj :
    rm -rf $(objs)

endif

.PHONY: all cleanobj

【讨论】:

    【解决方案4】:

    简单的方法是创建单独的构建目录并使用VPATH 允许您的(大部分未修改的)Makefile 在单独的目录中构建原始源代码。

    稍微困难的方法是修改你的 Makefile 以重写目标.o 和可执行文件到子目录中。例如:

    NODE = 1
    OBJDIR = obj.node$(NODE)
    SRC = main.c comm.o
    OBJ = $(SRC:%.c=$(OBJDIR)/%.o)
    

    然后您的目标重新调用您的 Makefile 并设置 NODE

    【讨论】:

      【解决方案5】:

      创建一个可以创建所有三个构建的批处理文件或 shell 脚本。比如:

      make node1
      <if needed copy your executable to a different directory>
      <clean all objs from make node1>
      make node2
      <if needed copy your executable to a different directory>
      <clean all objs from make node1>
      make node3
      <if needed copy your executable to a different directory>
      <clean all objs from make node1>
      

      all_node 构建规则调用此批处理文件或shell 脚本。

      【讨论】:

        猜你喜欢
        • 2022-06-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-08
        • 1970-01-01
        相关资源
        最近更新 更多