【问题标题】:Compile two targets with one Makefile用一个 Makefile 编译两个目标
【发布时间】:2017-02-12 13:45:45
【问题描述】:

---底部的完整 Makefile ---

我目前正在完成一个项目,所以我将进入打包/编译部分。 我正在使用 Make,我的项目的特殊性在于它包含两个项目,每个项目都有一个 main()。

我想要第一个项目的二进制文件(名为“shell”)和第二个项目的二进制文件(名为“ls”)。我已编辑 Makefile 以分隔目标、源文件等。以下是重要的几行:

-- Projects --
TARGET_SHELL = shell
TARGET_LS = ls

-- Directories --
SOURCE = ./src
BIN = ./bin
DIRLIST = ${SOURCE} ${BIN}

-- Targets --
BINSHELL = ${TARGET_SHELL:%=${BIN}/%}
BINLS = ${TARGET_LS:%=${BIN}/%}

-- Files --
SRC_SHELL = ${wildcard ${SOURCE}/execution.c ${SOURCE}/shell.c}
SRC_LS = ${wildcard ${SOURCE}/commande_ls.c}
INT_SHELL = ${wildcard ${SOURCE}/execution.h}
INT_LS = ${wildcard ${SOURCE}/commande_ls.h}
OBJ_SHELL = ${SRC_SHELL:%.c=%.o}
OBJ_LS = ${SRC_LS:%.c=%.o}

-- Rules --
all : ${BINSHELL} ${BINLS}

-- Binaries --
${BIN}/${TARGET_SHELL} : ${${TARGET_SHELL}:%=${SOURCE}/%}
${BIN}/${TARGET_LS} : ${${TARGET_LS}:%=${SOURCE}/%}

${BIN}/% : $(OBJ_SHELL)
    @echo
    @echo Linking bytecode : $@
    @echo ----------------
    @echo
    ${CC} -o $@ $^ ${LDFLAGS}
    @echo
    @echo Done
    @echo

“make”命令完美运行。最后,我有两个二进制文件,一个名为“shell”,另一个名为“ls”。不错!

但实际上,这两个二进制文件完全一样,都是执行“shell”项目。我希望二进制“shell”执行“shell”项目,而名为“ls”的二进制文件执行“ls”项目...

我知道我必须编辑 Makefile 的结尾,但我不知道是什么:(

谢谢

#/// @file 
#/// @brief Generic Makefile for the System 2 project.                                                 
#                                                                                                   
#/// @detail If you just add some library files used by the project.c program, you have nothing to change to compile them if sources are in the ./src directory. To add a new binary, just add the name of the main file in the TARGETS variable.             


#Nom du project
TARGET_SHELL = shell
TARGET_LS = ls

##############
# Constantes #
##############

# Repertoires
SOURCE = ./src
BIN = ./bin
DOCPATH = ${SOURCE}/dox
DOCTARGET = ./doc
DIRLIST = ${SOURCE} ${BIN}
#DEP = ${SOURCE}/depend
#DIRLIST = ${SOURCE} ${BIN} ${OPT} ${DEP}

# Cibles
BINSHELL = ${TARGET_SHELL:%=${BIN}/%}
BINLS = ${TARGET_LS:%=${BIN}/%}

# Commandes
CC = gcc

# Options
CFLAGS = -O0 -g -W -Wall -Wextra -Wconversion -Werror -mtune=native  -march=native  -std=c99  -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700
LDFLAGS = -lm -W -Wall -pedantic -L. -lm

# Fichiers
DOX = ${wildcard ${DOCPATH}/*.dox} # Sources
SRC_SHELL = ${wildcard ${SOURCE}/divers.c ${SOURCE}/commandes_externes.c ${SOURCE}/commandes_internes.c ${SOURCE}/entities.c ${SOURCE}/execution.c ${SOURCE}/parse.c ${SOURCE}/shell.c} # Sources
SRC_LS = ${wildcard ${SOURCE}/commande_ls.c}
INT_SHELL = ${wildcard ${SOURCE}/divers.h ${SOURCE}/commandes_externes.h ${SOURCE}/commandes_internes.h ${SOURCE}/execution.h ${SOURCE}/parse.h} # Interfaces
INT_LS = ${wildcard ${SOURCE}/commande_ls.h}
OBJ_SHELL = ${SRC_SHELL:%.c=%.o}        # Objets
OBJ_LS = ${SRC_LS:%.c=%.o}

##########
# Regles #
##########

# ALL
all : ${BINSHELL} ${BINLS}

# CLEAN
clean :
    @echo
    @echo Cleaning : object files
    @echo --------
    @echo
    rm -f ${OBJ_SHELL}
    rm -f ${OBJ_LS}

clean-doc :
    @echo
    @echo Cleaning : object files
    @echo --------
    @echo
    rm -fr ${DOCTARGET}

clean-emacs :
    @echo
    @echo Cleaning : emacs back-ups
    @echo --------
    @echo
    rm -f ${SOURCE}/*~
    rm -f ${SOURCE}/\#*\#
    rm -f *~
    rm -f \#*\#

clean-bin :
    @echo
    @echo Cleaning : binaries
    @echo --------
    @echo
    rm -f ${BINSHELL}
    rm -f ${BINLS}

distclean : clean clean-emacs clean-bin


dirs : 
    @for dir in ${DIRLIST} ;\
    do \
        echo Creating directory : $${dir} ;\
        echo ------------------ ;\
        if test -d $${dir} ;\
        then \
        echo Directory already exists ;\
        else mkdir -p $${dir} ;\
        fi ;\
        echo Done ;\
        echo ;\
    done

# Binaires
${BIN}/${TARGET_SHELL} : ${${TARGET_SHELL}:%=${SOURCE}/%}
${BIN}/${TARGET_LS} : ${${TARGET_LS}:%=${SOURCE}/%}

${BIN}/% : $(OBJ_SHELL)
    @echo
    @echo Linking bytecode : $@
    @echo ----------------
    @echo
    ${CC} -o $@ $^ ${LDFLAGS}
    @echo
    @echo Done
    @echo

# Regles generiques
%.o : %.c %.h 
    @echo
    @echo Compiling $@
    @echo --------
    @echo
    $(CC) $(CFLAGS) -c $< -o $@

# Documentation 
doc : ${SRC} ${INT} ${DOX}
    doxygen; doxygen

#############################
# Inclusion et spécificités #
#############################

.PHONY : all clean clean-doc clean-emacs clean-bin distclean doc

【问题讨论】:

  • 你没有意义的东西,如果你精确一个文件,为什么要使用通配符?这不是一个有效的 makefile。
  • 是的,我忘了删除通配符,谢谢。而且我的文件是有效的,我只是没有把它的全部内容放在我的帖子上。
  • -- Projects -- 不是有效评论
  • 我知道这只是为了这篇文章,让我的 Makefile 更具可读性:)
  • 如果您愿意,请使用正确的方式来注释 makefile # -- Projects --,但不要使您的 makefile 无效。

标签: shell makefile


【解决方案1】:

非常动态的 makefile 带来一些乐趣:

#
# Boilerplate.
#
define add_target
    $(info add_target($1))
    $(eval $(eval_args))
    $(eval $(call eval_args,$1,\
        OBJDIR := $(firstword $($1.OBJDIR) ./objs/$1),\
    ))
    $(eval $(call eval_args,$1,\
        objs := $(obj_from_source),
    ))
    $(eval $1 := $($1.TARGET))

    TARGETS += $($1)
    PHONY_TARGETS += $1
    CLEAN_TARGETS += clean_$1

    .PHONY: clean_$1
    clean_$1:; rm -rf $($1.OBJDIR) $($1)

    .PHONY: $1
    $1: $($1)

    $($1): target:=$1
    $($1): $($1.objs); $$(if $$(wildcard $$(@D)),,mkdir -p $$(@D) && )$$(add_target.link)
    $($1.objs):; $$(if $$(wildcard $$(@D)),,mkdir -p $$(@D) && )$$(add_target.compile)
    $(foreach $1.SOURCES,$($1.SOURCES),$(eval $(obj_from_source): $($1.SOURCES)))

    $(info end)
endef

void :=
space := $(void) $(void)
obj_from_source = $(addprefix $($1.OBJDIR)/,$(addsuffix .o,$(basename $(notdir $($1.SOURCES)))))
eval_args = $(foreach i,2 3 4 5 6 7 8 9,$(call eval_arg,$1,$(strip $($i))))
eval_arg = $(if $2,$(info $(space)$(space)$1.$2)$(eval $1.$2))

# Link command line
add_target.link = $(CC) $($(target).LDLAGS) -o $@ $^

# Compile command line
add_target.compile = $(CC) -c -o $@ $($(target).CFLAGS) $<


# -- Directories --
SOURCE := ./src
BIN := ./bin


# Add 'shell' target to the project
$(eval $(call add_target,shell,\
    TARGET := $(BIN)/shell,\
    SOURCES += ${SOURCE}/execution.c,\
    SOURCES += ${SOURCE}/shell.c,\
    CFLAGS := -Wall -I./include,\
))

# Add 'ls' target to the project
$(eval $(call add_target,ls,\
    TARGET := $(BIN)/ls,\
    SOURCES := $(addprefix ${SOURCE}/,execution.c commande_ls.c),\
    CFLAGS := -I./include,\
))


all: ${PHONY_TARGETS}
.PHONY: all

clean: | $(CLEAN_TARGETS)
.PHONY: clean

环境:

$ find
.
./include
./include/execution.h
./src
./src/commande_ls.c
./src/execution.c
./src/shell.c

源文件:

$ for f in `find -type f`; do echo $f; cat $f; echo; done
./include/execution.h
void workload();

./src/commande_ls.c
#include <stdio.h>
#include "execution.h"
int main() {
    printf("Welcome to ls\n");
    workload();
}
./src/execution.c
#include <stdio.h>
#include "execution.h"
void workload() {
    printf("Hello from %s\n", __FILE__);
}

./src/shell.c
#include <stdio.h>
#include "execution.h"
int main() {
    printf("Welcome to shell\n");
    workload();
}

构建所有目标:

$ make -f ../Makefile.sample
add_target(shell)
  shell.TARGET := ./bin/shell
  shell.SOURCES += ./src/execution.c
  shell.SOURCES += ./src/shell.c
  shell.CFLAGS := -Wall -I./include
  shell.OBJDIR := ./objs/shell
  shell.objs := $(obj_from_source)
end
add_target(ls)
  ls.TARGET := ./bin/ls
  ls.SOURCES := ./src/execution.c ./src/commande_ls.c
  ls.CFLAGS := -I./include
  ls.OBJDIR := ./objs/ls
  ls.objs := $(obj_from_source)
end
mkdir -p objs/shell && cc -c -o objs/shell/execution.o -Wall -I./include src/execution.c
cc -c -o objs/shell/shell.o -Wall -I./include src/shell.c
mkdir -p bin && cc  -o bin/shell objs/shell/execution.o objs/shell/shell.o
mkdir -p objs/ls && cc -c -o objs/ls/execution.o -I./include src/execution.c
cc -c -o objs/ls/commande_ls.o -I./include src/commande_ls.c
cc  -o bin/ls objs/ls/execution.o objs/ls/commande_ls.o

运行目标:

$ ./bin/ls.exe; ./bin/shell.exe
Welcome to ls
Hello from src/execution.c
Welcome to shell
Hello from src/execution.c

清理 ls 并再次构建所有目标(只是为了好玩):

$ make -f ../Makefile.sample clean_ls
add_target(shell)
  shell.TARGET := ./bin/shell
  shell.SOURCES += ./src/execution.c
  shell.SOURCES += ./src/shell.c
  shell.CFLAGS := -Wall -I./include
  shell.OBJDIR := ./objs/shell
  shell.objs := $(obj_from_source)
end
add_target(ls)
  ls.TARGET := ./bin/ls
  ls.SOURCES := ./src/execution.c ./src/commande_ls.c
  ls.CFLAGS := -I./include
  ls.OBJDIR := ./objs/ls
  ls.objs := $(obj_from_source)
end
rm -rf ./objs/ls ./bin/ls

$ make -f ../Makefile.sample
add_target(shell)
  shell.TARGET := ./bin/shell
  shell.SOURCES += ./src/execution.c
  shell.SOURCES += ./src/shell.c
  shell.CFLAGS := -Wall -I./include
  shell.OBJDIR := ./objs/shell
  shell.objs := $(obj_from_source)
end
add_target(ls)
  ls.TARGET := ./bin/ls
  ls.SOURCES := ./src/execution.c ./src/commande_ls.c
  ls.CFLAGS := -I./include
  ls.OBJDIR := ./objs/ls
  ls.objs := $(obj_from_source)
end
mkdir -p objs/ls && cc -c -o objs/ls/execution.o -I./include src/execution.c
cc -c -o objs/ls/commande_ls.o -I./include src/commande_ls.c
cc  -o bin/ls objs/ls/execution.o objs/ls/commande_ls.o

请注意$(add_target) 函数有多方便。它提供了根据需要向项目添加尽可能多的目标的方式,而无需重复代码。仍然配置目标构建选项非常灵活。

应该与 GNU Make 3.81 及更高版本一起使用。享受吧!

【讨论】:

  • 看起来很棒!我会在几分钟内尝试,如果成功了会告诉你
  • 不幸的是,它不起作用,因为我还必须在我的 .c 文件中包含所需的 .h 文件。在您的 Makefile 中,我必须在哪里将 .h 文件包含到两个目标中?非常感谢
  • @John Kerman,通过处理#includes-s 更新了我的答案。请注意,我刚刚调整了传递给 $(add_target) 函数的 CFLAGS 属性的值,以指示编译器在哪里查找标头。锅炉制造没有变化。
  • 它有效,至少对于“ls”来说是这样;)我正在尝试“shell”。顺便问一下,为什么你在 ls 目标中使用addprefix 而不是在 shell 目标中?
  • @John Kerman,addprefix 在一种情况下,SOURCES += 在另一种情况下只是为了展示解决方案的灵活性。请记住add_target 只是一个起点。与具有隐式规则的常见解决方案相比,这是一个非常好的起点:),但仍然如此。您可能希望扩展它,使其能够跟踪从源代码的#include 指令引用的 .h 文件中的更改并重建 .o 文件。一旦您了解了 add_target 的工作原理,您就可以对其进行扩展以更好地满足您的需求。
【解决方案2】:

你有没有尝试过这样的事情:

SUBDIRS := common programs

all: subdir

ifdef SUBDIRS
.PHONY: subdir $(SUBDIRS)
subdir: $(SUBDIRS)

$(SUBDIRS):
    $(MAKE) -s -C $@ <--  ${BIN...
endif

子目录 --> 目标...

【讨论】:

  • 我不明白?在我的情况下,SUBDIRS 代表什么?我的所有源文件只有一个文件夹
  • 递归 makefile 绝对是邪恶的。
  • 用或TARGET替换SUBDIRS,这只是一个使用示例
  • 用TARGET代替SUBDIRS,这只是一个使用列表的例子
猜你喜欢
  • 1970-01-01
  • 2016-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-17
  • 1970-01-01
相关资源
最近更新 更多