使用 GNU Make 输出平面对象文件目录结构

发布于 2024-08-03 12:06:29 字数 578 浏览 5 评论 0原文

我有一个使用 GNU Make 的 C++ 小项目。我希望能够将以下源文件: 转换

src/
  a.cpp
  b/
    b.cpp
  c/
    c.cpp

为以下输出结构(此时我不关心重复项):

build/
  a.o
  b.o
  c.o

到目前为止,我有以下内容,不幸的是,这将 .o 和 .d 放在了旁边对于每个 .cpp:

OBJS            :=      $(foreach file,$(SRCS),$(file).o)
DEPS            :=      $(patsubst %.o,%.d,$(OBJS))
sinclude $(DEPS)

$(OBJS) : %.o : %.cpp
        @echo Compiling $<
        $(CC) $(CC_FLAGS) $(INCS) -MMD -o $@ $<  

我知道 $(notdir ...) 函数,但此时我使用它来过滤对象的努力失败了。有人能解释一下吗?这似乎是相当合理的事情。

I have a C++ small project using GNU Make. I'd like to be able to turn the following source files:

src/
  a.cpp
  b/
    b.cpp
  c/
    c.cpp

into the following output structure (I'm not concerned about duplicates at this point):

build/
  a.o
  b.o
  c.o

So far I have the following, which unfortunately puts the .o and .d right next to each .cpp:

OBJS            :=      $(foreach file,$(SRCS),$(file).o)
DEPS            :=      $(patsubst %.o,%.d,$(OBJS))
sinclude $(DEPS)

$(OBJS) : %.o : %.cpp
        @echo Compiling 
lt;
        $(CC) $(CC_FLAGS) $(INCS) -MMD -o $@ 
lt;  

I'm aware of the $(notdir ...) function, but at this point my efforts to use it to filter the objects has failed. Can anyone shed some light on this? It seems like fairly reasonable thing to do.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

金橙橙 2024-08-10 12:06:30

您可能不太喜欢这种方法,但是:

AUTOMAKE_OPTIONS =

在 Makefile.am 中效果很好。只是说你不需要手写所有内容。

You might not particulary like this approach, but:

AUTOMAKE_OPTIONS =

does the trick quite well in a Makefile.am. Just sayin' that you don't need to write everything by hand.

梦一生花开无言 2024-08-10 12:06:29

至少有两种方法可以做到这一点。首先(也是我建议的)是您可以将构建目录添加到目标名称(即使使用模式规则时)。例如:

$(OBJS) : build/%.o : %.cpp

其次,您可以使用 VPATH 变量告诉 make 在不同的目录中搜索先决条件。这可能是更常用(过度)使用的方法。它至少有一个严重的缺点,那就是如果你照着做,后来遇到“重复”的问题,就没有办法解决问题。使用前一种方法,您始终可以镜像构建目录下的源目录结构,以避免重复冲突。

编辑:我之前的回答在细节上有点简短,所以我将对其进行扩展以表明这实际上像广告中那样有效。这是一个完整的工作示例 Makefile,它使用上述第一种技术来解决问题。只需将其粘贴到 Makefile 中并运行 make ——它将完成其余的工作并表明这确实有效。

编辑:我不知道如何让SO在我的答案文本中允许使用制表符(它用空格替换它们)。复制并粘贴此示例后,您需要将命令脚本中的前导空格转换为制表符。

BUILD_DIR := build

SRCS := \
    a.c \
    b.c \
    c.c \
    a/a.c \
    b/b.c \
    c/c.c

OBJS := ${SRCS:%.c=${BUILD_DIR}/%.o}

foo: ${OBJS}
    @echo Linking $@ using $?
    @touch $@

${BUILD_DIR}/%.o: %.c
    @mkdir -p $(dir $@)
    @echo Compiling 
lt; ...
    @touch $@

${SRCS}:
    @echo Creating $@
    @mkdir -p $(dir $@)
    @touch $@

.PHONY: clean
clean:
    rm -f foo
    rm -f ${OBJS}

特别要注意的是,存在具有重复名称的源文件(ac 和 a/ac、bc 和 b/bc 等),这不会导致任何问题。另请注意,没有使用 VPATH,由于其固有的限制,我建议避免使用 VPATH。

There are at least two ways you can do this. First (and what I'd recommend) is you can add the build directory to the target names (even when using a pattern rule). For example:

$(OBJS) : build/%.o : %.cpp

Second, you can use the VPATH variable to tell make to search a different directory for prerequisites. This is probably the more commonly (over) used approach. It has at least one serious drawback, and that is if you go with it, and later run into problems with "duplicates", there's no way to solve the problem. With the former approach, you can always mirror the source directory structure underneath the build directory to avoid duplicates clashing.

Edit: My previous answer was a little short on detail, so I will expand upon it to show that this actually works as advertised. Here is a complete working example Makefile that uses the first technique described above to solve the problem. Simply paste this into a Makefile and run make -- it will do the rest and show that this does in fact work.

Edit: I can't figure out how to get SO to allow tab characters in my answer text (it replaced them with spaces). After copying and pasting this example, you'll need to convert the leading spaces in the command scripts into tabs.

BUILD_DIR := build

SRCS := \
    a.c \
    b.c \
    c.c \
    a/a.c \
    b/b.c \
    c/c.c

OBJS := ${SRCS:%.c=${BUILD_DIR}/%.o}

foo: ${OBJS}
    @echo Linking $@ using $?
    @touch $@

${BUILD_DIR}/%.o: %.c
    @mkdir -p $(dir $@)
    @echo Compiling 
lt; ...
    @touch $@

${SRCS}:
    @echo Creating $@
    @mkdir -p $(dir $@)
    @touch $@

.PHONY: clean
clean:
    rm -f foo
    rm -f ${OBJS}

In particular, note that there are source files with duplicate names (a.c and a/a.c, b.c and b/b.c, etc) and that this doesn't cause any problems. Also note there is no use of VPATH, which I recommend to avoid using due to its inherent limitations.

睫毛上残留的泪 2024-08-10 12:06:29
vpath %.cpp src src/b src/c

然后引用源文件而不使用其目录名; Make 将搜索 vpath

vpath %.cpp src src/b src/c

Then refer to source files without their directory name; Make will search the vpath.

多情癖 2024-08-10 12:06:29

按照最初的要求创建平面目录结构。

确实使用vpath来追踪源文件,但所有的簿记都是从SRC列表中自动完成的。

SRC = a/a.c a/aa.c b/b.c
TARGET = done

FILES = $(notdir $(SRC) )
#make list of source paths, sort also removes duplicates
PATHS = $(sort $(dir $(SRC) ) )

BUILD_DIR = build
OBJ = $(addprefix $(BUILD_DIR)/, $(FILES:.c=.o))
DEP = $(OBJ:.o=.d)

# default target before includes
all: $(TARGET)

include $(DEP)

vpath %.c $(PATHS)

# create dummy dependency files to bootstrap the process
%.d:
    echo a=1 >$@

$(BUILD_DIR)/%.o:%.c
    echo $@: 
lt; > $(patsubst %.o,%.d,$@)
    echo 
lt; >$@

$(TARGET): $(OBJ)
    echo $^ > $@

.PHONY: clean
clean:
    del $(BUILD_DIR)/*.o
    del $(BUILD_DIR)/*.d

抱歉,回声很丑,但我只有我的胜利盒来测试它。

Creating the flat directory structure as initially requested.

Does use vpath to track down the source files, but all the bookeeping is done automagically from the SRC list.

SRC = a/a.c a/aa.c b/b.c
TARGET = done

FILES = $(notdir $(SRC) )
#make list of source paths, sort also removes duplicates
PATHS = $(sort $(dir $(SRC) ) )

BUILD_DIR = build
OBJ = $(addprefix $(BUILD_DIR)/, $(FILES:.c=.o))
DEP = $(OBJ:.o=.d)

# default target before includes
all: $(TARGET)

include $(DEP)

vpath %.c $(PATHS)

# create dummy dependency files to bootstrap the process
%.d:
    echo a=1 >$@

$(BUILD_DIR)/%.o:%.c
    echo $@: 
lt; > $(patsubst %.o,%.d,$@)
    echo 
lt; >$@

$(TARGET): $(OBJ)
    echo $^ > $@

.PHONY: clean
clean:
    del $(BUILD_DIR)/*.o
    del $(BUILD_DIR)/*.d

Sorry about the ugly echo's but I only had my win box to test it on.

草莓酥 2024-08-10 12:06:29

这是针对 Win32 mingw32-make 的。这是有效的。
最重要的部分是

-mkdir $(patsubst %/,%,$(dir $@))

win32 的 。我们需要去掉 win32 后面的 / 。

GENERATED_DIRS = a b

# Dependency generator function
mkdir_deps =$(foreach dir,$(GENERATED_DIRS),$(dir)/.mkdir.done)

# Target rule to create the generated dependency.
# And create the .mkdir.done file for stop continuous recreate the dir
%/.mkdir.done: # target rule
    -mkdir $(patsubst %/,%,$(dir $@))
    echo $(patsubst %/,%,$(dir $@)) >$@

all: $(mkdir_deps)
    @echo Begin

clean:
    @echo Cleaning

This is for Win32 mingw32-make. it's works.
The most important part is

-mkdir $(patsubst %/,%,$(dir $@))

for win32. We need to strip the trailling / for win32.

GENERATED_DIRS = a b

# Dependency generator function
mkdir_deps =$(foreach dir,$(GENERATED_DIRS),$(dir)/.mkdir.done)

# Target rule to create the generated dependency.
# And create the .mkdir.done file for stop continuous recreate the dir
%/.mkdir.done: # target rule
    -mkdir $(patsubst %/,%,$(dir $@))
    echo $(patsubst %/,%,$(dir $@)) >$@

all: $(mkdir_deps)
    @echo Begin

clean:
    @echo Cleaning
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文