使用一个Makefile编译两个目标

时间:2017-02-12 13:45:46

标签: shell makefile

---底部的完整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

2 个答案:

答案 0 :(得分:0)

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

SUBDIRS := common programs

all: subdir

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

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

SUBDIRS - &gt; TARGET ...

答案 1 :(得分:0)

非常动态的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及以上版本。享受!

相关问题