Makefiles:子目录和类似的文件名

Makefiles:子目录和类似的文件名,makefile,Makefile,为了理解C/C++开发工具并停止依赖IDE,切换到VisualStudio代码。为此,我尝试使用makefile,因为它允许通过命令行在目标设备上运行编译(无GUI==无IDE)。到目前为止,我已经成功地创建了一个通用的Makefile,它将所有.cpp文件编译成相应的.o文件,然后将它们链接在一起。它适用于将所有源存储在单个目录中的小项目。现在我必须移植我正在工作的Xcode项目 问题是源文件存储在目录树中(没有单个目录),可能是C和C++。有些文件具有相似的文件名,但位于不同的文件夹中。从C

为了理解C/C++开发工具并停止依赖IDE,切换到VisualStudio代码。为此,我尝试使用makefile,因为它允许通过命令行在目标设备上运行编译(无GUI==无IDE)。到目前为止,我已经成功地创建了一个通用的Makefile,它将所有
.cpp
文件编译成相应的
.o
文件,然后将它们链接在一起。它适用于将所有源存储在单个目录中的小项目。现在我必须移植我正在工作的Xcode项目

问题是源文件存储在目录树中(没有单个目录),可能是
C
C++
。有些文件具有相似的文件名,但位于不同的文件夹中。从C++角度来说,它意味着类具有相同的名称,但名称空间不同。各种IDE都很容易处理这个问题,但是Makefile给了我各种各样的问题,因为我还不是make专家

我尝试在每个目录中创建Makefile(我失败了),但后来我读到这被认为是一种不好的方法,所以我切换到单个Makefile方法。有人说我应该切换到CMake,但我认为如果不先了解Makefile的创建,这是毫无意义的,因为CMake最终会创建一个。它还允许在没有CMake和其他酷工具的设备上构建和安装(例如,如果没有互联网连接来下载CMake)

以下是一个基本想法:

- project-name/
  - application/
    - core/
      - loader.hpp
      - loader.cpp
      - ...
    - loader.hpp
    - loader.cpp
    - ...
  - hardware/
    - loader.hpp
    - loader.cpp
    - ...
  - some-c-library
    - library.h
    - library.c
    - ...
  - main.cpp
- project-name.xcodeproj
- Makefile

TR&DL:无法生成复杂的生成文件。GNU手册很难理解,在线博客/教程大多只涉及基本内容。

我真的不确定你是否需要过于复杂。当然,你可以让MaCfile文件搜索你的C++目录文件,但如果你添加了一个你不想编译的新文件,

不过,你可以让事情变得更简单,而不会太复杂。将源文件列表分配给变量-这样您可以在需要时随时引用它们

CPPSOURCES=hardware/loader.cpp application/core/loader.cpp main.cpp
CSOURCES=some-c-library/library.c
然后将这些文件名转换为对象文件名-这只是用.o等替换.cpp

CPPOBJS=$(CPPSOURCES:.cpp=.o)
COBJS=$(CSOURCES:.c=.o)
<> P>有标准变量,用于指定哪些标志传递给C++编译器和C编译器< /P>
CXXFLAGS-g
CFLAGS-g
然后,您就有了一个构建项目的规则
$@
是规则正在构建的对象(即“myproject”)的名称,
$^
是依赖项列表

myproject: $(COBJS) $(CPPOBJS)
   $(CXX) $(CXXFLAGS) -o $@ $^
Make附带了一系列默认规则,因此它已经知道,如果您要求它构建“some/where/deep/in/my/project/somefile.o”,它将查找“some/where/deep/in/my/project/somefile.cpp”

您可以添加一个规则来删除所有对象文件-这就是为什么使用变量很方便的原因

clean:
    rm $(COBJS) $(CXXOBJS)
您需要担心的另一件事是依赖性,如下面的示例,它告诉make,每当“hardware/loader.hpp”或“application/core/loader.hpp”更新时,它都需要构建“hardware/loader.o”

hardware/loader.o: hardware/loader.hpp application/core/loader.hpp

这可能是您想要研究自动生成的一个领域,因为很容易遗漏依赖项,然后它就不会在头中拾取任何更改。如注释中所述,当您使用-M命令行选项构建代码时,gcc/g++可以在中为您生成文件,您可以在Makefile中使用
include
指令来添加这些文件。

这看起来很有帮助,我知道您想要理解Makefile,但对于这种复杂的场景,我强烈推荐使用makefile生成器(比如CMake)。一个原因是原始Makefiles不会自动跟踪依赖项:如果添加新的
#include
,还必须记住更新相应的Makefile以在该标头上添加依赖项,否则您的源文件可能无法按预期编译,您在尝试找出链接器错误时会感到头疼。您不需要CMake来自动生成依赖项——您只需在gcc中使用-M标志即可。您面临什么样的问题,因为我看不出当前设置会有什么复杂之处——除了Makefile应该在项目中之外directory@Vroomfondel: 重复的文件名并不少见。假设文件名不会(或将来不会)冲突,这不是一个可扩展性很强的解决方案,因此我个人不鼓励不处理冲突的做法。将路径名放在include指令等中以避免冲突非常简单。