【问题标题】:organize project and specify directory for object files in Makefile在 Makefile 中组织项目并指定目标文件的目录
【发布时间】:2009-08-14 12:52:39
【问题描述】:

这是我的两个问题:

  1. 我现在正在学习使用 CVS 管理我的代码,我只想为我的 C++ 文件、Makefile 和 bash 以及 python 脚本创建一个存储库,而不是目标文件和可执行文件。所以我在我的项目目录下做了几个子目录:src、bin、scripts、results和data。

    我将 C++ 文件和 Makefile 放在 ~/myproject/src 下,将 Bash 和 Python 脚本放在 ~/myproject/scripts 下,将对象和可执行文件放在 ~/myproject/bin 下。我希望只有 src 和脚本下的文件将通过 CVS 更新。我想知道你是如何组织你的项目的?只是希望养成一些好习惯。

  2. 由于我将 C++ 文件和 Makefile 放入 ~/myproject/src 并将对象和可执行文件放入 ~/myproject/bin,因此我必须在 Makefile 中指定目录。这就是我正在做的事情

生成文件:

...
BIN_DIR=/home/myproject/bin/

all: $(BIN_DIR)myexecutable TAGS

TAGS: *.cc *.h
    etags --members --declarations -l c++ *.cc *.h

$(BIN_DIR)myexecutable: $(BIN_DIR)myobject.o
    $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)

Makefile.depend: *.h *.cc Makefile
    $(CXX) -M $(CXXFLAGS) *.cc > Makefile.depend

clean:
    \rm -f $(BIN_DIR)myexecutable $(BIN_DIR)*.o Makefile.depend TAGS`

但是这会报错

make: *** 没有规则来制作目标/home/myproject/bin/myobject.o', needed by /home/myproject/bin/myexecutable'。

如何在 Makefile 中为对象和可执行文件指定与 C++ 文件不同的目录?

【问题讨论】:

  • 请将 Makefile 中的摘录缩进四个空格。这将为它提供正确的格式和语法突出显示。
  • 似乎某处有一个错误阻止将代码放在列表之后。我添加了“Makefile:”作为解决方法。

标签: c++ project-management makefile cvs


【解决方案1】:

如果你想学习make,GNU make manual非常好,既可以作为参考,也可以作为教程。您可能需要考虑使用 patsubst 命令。以下是我自己使用它的一个 makefile 的精简版本:

OUT = bin/csvfix.exe
CC = g++
IDIR = inc
ODIR = obj
SDIR = src
INC = -Iinc -I../alib/inc
LIBS = ../alib/lib/alib.a -lodbc32 

_OBJS = csved_atable.o \
        csved_case.o \
        csved_cli.o \
        csved_command.o \
        csved_date.o \

OBJS = $(patsubst %,$(ODIR)/%,$(_OBJS))

$(ODIR)/%.o: $(SDIR)/%.cpp 
    $(CC) -c $(INC) -o $@ $< $(CFLAGS) 

$(OUT): $(OBJS)
    $(CC) -o $@ $^ $(CFLAGS) $(LIBS)
    strip $(OUT)

clean:
    rm -f $(ODIR)/*.o $(OUT)

【讨论】:

    【解决方案2】:
    1. 您可以根据需要将文件保存在不同的目录中,但这不是必需的。将文件或目录添加到 CVS 存储库一次,CVS 将无限期地保留它。从那时起,您可以对其进行更新,签入,等等。如果您不将目标文件添加到存储库,CVS 将不会触及它。如果您想添加整个目录树,并且您习惯将对象保存在其中,那么只需在执行此操作之前先 make clean。

    2. Make 是一个很棒的工具,但它有一些明显的缺陷。您所描述的是经典问题之一:Make 擅长使用源 there 来制作 here 的东西,但反之则不然。您可以通过以下几种方法来做您想做的事情。

    A) 在你的二进制目录中运行 make:

    ... 全部:我的可执行标签 我的可执行文件:myobject.o $(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS) VPATH = /home/myproject/src ...

    cd ~/myproject/bin
    make -f ../src/makefile

    B)通过暴力将对象放在bin目录中:

    $(BIN_DIR)%.o: %.cc $(CXX) $(CXXFLAGS) -c -o $@ $^

    这会给您带来 Makefile.depend 的问题,您可以通过多种方式处理它。

    C) 学习一些更高级的 Make 技术。你可能不应该尝试这个。

    【讨论】:

    • 如果您采用方法 B),您将如何解决 Makefile 依赖项的问题?
    • @frankster,我可能会修改Makefile.depend 命令以将$(BIN_DIR) 添加到目标文件的名称之前。一点点 sed 就可以了。
    • 谢谢,@Beta (1) 我想知道“Make 擅长使用那里的源来制作东西”的原因是否是您在 B 中描述的“Makefile.depend 的问题” ? (2) 按照您建议的“Makefile.depend 问题”的方式,您会将makefile 放在哪里?在src/,还是bin/,还是项目的根目录?见*.com/q/49836438/156458
    【解决方案3】:
    1. 您的目录结构似乎很合理。

    2. 我会制定一个明确的规则来执行编译器,比如

    TARGET_DIR=bin
    SRC_DIR=src
    CXX=g++
    CXXFLAGS=
    ETC=
    
    OBJS=$(TARGET_DIR)/test.o
    
    all: $(OBJS)
    
    $(TARGET_DIR)/%.o: $(SRC_DIR)/%.cc
            $(CXX) -c -o $@ $(CXXFLAGS) $(ETC) $<
    

    【讨论】:

    • 我会感谢您对否决票发表评论,以便我可以提高自己:)
    • 不知道是谁给你投票的,不是我。 :) 如果你有很多 .cc 文件,为每个目标文件指定一个规则很乏味,不是吗?
    • 该规则是通用的,因此适用于任何 .cc 文件。我已经使用目标对象列表更新了示例 Makefile-code。只需在此处指定额外的 .o 文件,它们将使用相同的规则进行编译。
    • 考虑一下所有成功使用 CVS 的数千个项目。
    • @Neil:对不起。我的印象是每个人都同意 CVS 是过去的遗物。我可能错了。无论如何,这是一个有用的提示,但由于它不是对问题中任何内容的严格回答,我删除了可能有问题的提示。
    【解决方案4】:

    使用automakeautoconf 构建您的项目。

    至于文件的结构,只需看看任何大型开源 C++ 应用程序即可。任何 KDE 应用程序 在这件事上会做得很好。如果您发现使用 C++ 和 Python 的应用程序更好。

    【讨论】:

      【解决方案5】:

      为什么不选择 eclipse,它在管理大型项目时非常流行和方便。您可以在 eclipse 中创建一个新项目,将代码从其他项目导入导出到项目中,也可以为您进行版本控制等。无需编写您的 make 文件,eclipse 会使用您在 GUI 中提到的首选项为您完成。 如果您参与了 C++ 项目,只需在 eclipse 上安装 CDT 插件即可。

      【讨论】:

      • 根本不回答问题。
      最近更新 更多