Makefile没有创建到正确的文件夹
Makefile does not create to the right folder
我有以下项目目录结构:
drwxr-xr-x+ 1 account Domain Users 0 Aug 20 16:16 ./
drwxr-xr-x+ 1 account Domain Users 0 Aug 20 08:48 ../
drwxr-xr-x+ 1 account Domain Users 0 Aug 20 10:55 include/
-rw-r--r-- 1 account Domain Users 597 Aug 20 16:16 Makefile
drwxr-xr-x+ 1 account Domain Users 0 Aug 20 10:55 obj/
drwxr-xr-x+ 1 account Domain Users 0 Aug 20 10:55 src/
在src目录下:main.cpp foo.cpp bar.cpp
在include文件夹:foo.h bar.h
当我运行下面的Makefile时,目标文件是在项目目录中创建的,而不是我从Makefile中期望的obj
目录:
1 ODIR = obj
2 SDIR = src
3 IDIR = include
4
5 _OBJS = main.o foo.o bar.o
6 OBJS = $(patsubst %,$(ODIR)/%,$(_OBJS))
7
8 CC = g++
9
10 CFLAGS = -w
11
12 PROG = program
13
14 #VPATH = src:include:obj:../src:../include:../obj
15
16 all: $(OBJS)
17 $(CC) $(CFLAGS) -I$(IDIR) $(OBJS) -o $(PROG)
18
19 $(ODIR)/main.o: $(SDIR)/main.cpp $(IDIR)/foo.h $(IDIR)/bar.h
20 $(CC) $(CFLAGS) -I$(IDIR) -c $(SDIR)/main.cpp
21
22 $(ODIR)/foo.o: $(SDIR)/foo.cpp $(IDIR)/foo.h
23 $(CC) $(CFLAGS) -I$(IDIR) -c $(SDIR)/foo.cpp
24
25 $(ODIR)/bar.o: $(SDIR)/bar.cpp $(IDIR)/bar.h
26 $(CC) $(CFLAGS) -I$(IDIR) -c $(SDIR)/bar.cpp
27
28 clean:
29 rm -f $(PROG) $(OBJS)
谁能告诉我为什么会这样?我的链接器没有看到目标文件,因为它认为文件在obj目录下。
详细说明一下WhozCraig的回答:
从这个规则开始:
$(ODIR)/main.o: $(SDIR)/main.cpp $(IDIR)/foo.h $(IDIR)/bar.h
$(CC) $(CFLAGS) -I$(IDIR) -c $(SDIR)/main.cpp
命令($(CC) ...
)没有指定输出文件,所以编译器会把生成的目标文件(main.o
)放在工作目录中,也就是你调用Make的目录,也就是项目目录。注意Make和编译器之间的对话并不多。编译器知道它应该扫描哪些源文件,但是没有人告诉它obj/
,所以它从源文件名推断目标文件名(main.o
);Make知道目标应该是obj/main.o
,但它不知道编译器实际在做什么。(实际上,它不知道它正在执行的命令调用了编译器。)
我们可以通过在命令中添加一个术语来解决这个问题,指定目标文件名:
$(ODIR)/main.o: $(SDIR)/main.cpp $(IDIR)/foo.h $(IDIR)/bar.h
$(CC) $(CFLAGS) -I$(IDIR) -c $(SDIR)/main.cpp -o $(ODIR)/main.o
现在编译器将把main.o
放到正确的位置——Make没有注意到任何区别,它仍然只是向shell传递一个命令。
我们注意到这个规则中有很多冗余(例如$(ODIR)/main.o
拼写两次),所以我们通过使用自动变量来减少它:
$(ODIR)/main.o: $(SDIR)/main.cpp $(IDIR)/foo.h $(IDIR)/bar.h
$(CC) $(CFLAGS) -I$(IDIR) -c $< -o $@
其中$<
展开为先决条件列表中的第一个内容(即$(SDIR)/main.cpp
), $@
展开为目标名称(即$(ODIR)/main.o
)。由于稍后会清楚的原因,我们将标题依赖项拆分为同一个目标的单独规则:
$(ODIR)/main.o: $(IDIR)/foo.h $(IDIR)/bar.h
$(ODIR)/main.o: $(SDIR)/main.cpp $(IDIR)/foo.h $(IDIR)/bar.h
$(CC) $(CFLAGS) -I$(IDIR) -c $< -o $@
是的,我们可以做到。
现在我们来看对象规则:
$(ODIR)/main.o: $(IDIR)/foo.h $(IDIR)/bar.h
$(ODIR)/foo.o: $(IDIR)/foo.h
$(ODIR)/bar.o: $(IDIR)/bar.h
$(ODIR)/main.o: $(SDIR)/main.cpp
$(CC) $(CFLAGS) -I$(IDIR) -c $< -o $@
$(ODIR)/foo.o: $(SDIR)/foo.cpp
$(CC) $(CFLAGS) -I$(IDIR) -c $< -o $@
$(ODIR)/bar.o: $(SDIR)/bar.cpp
$(CC) $(CFLAGS) -I$(IDIR) -c $< -o $@
我们再次看到冗余——最后三条规则几乎完全相同!我们可以把它们做成一个模式规则:
$(ODIR)/main.o: $(IDIR)/foo.h $(IDIR)/bar.h
$(ODIR)/foo.o: $(IDIR)/foo.h
$(ODIR)/bar.o: $(IDIR)/bar.h
$(ODIR)/%.o: $(SDIR)/%.cpp
$(CC) $(CFLAGS) -I$(IDIR) -c $< -o $@
我们可以更进一步,但这一天就够了。
缺少编译命令的目标说明符。当执行this时:
$(CC) $(CFLAGS) -I$(IDIR) -c $(SDIR)/main.cpp
没有目标,所以默认是当前工作目录(在您的情况下,是Makefile所在的根文件夹)。
Gnu make提供了一个多个自动变量,用于在配方中进行替换,每个都提供一些配方的微粒,供您在形成命令时使用。请参阅此处了解完整的策略,但我相信您会想要这样的内容:
$(CC) $(CFLAGS) -I$(IDIR) -c -o $@ $(SDIR)/main.cpp
来自Gnu文档:
$@
规则目标的文件名。如果目标是则
$@
是归档文件的名称。在一个具有多个目标的模式规则(参见模式介绍)规则),$@
是引起规则配方的目标的名称待运行
或者类似的东西。
另外,有很多方法可以为您的项目构建自动依赖。一种常见的方法(尽管有点难以遵循)在StackOverflow上给出了这个答案。这个问题本身是基于这篇讨论自动依赖生成技术的论文。
它基本上归结为为每个源文件生成一个.d
文件,并且在.d文件中是通过-MMD
命令开关选项生成的头文件列表。详细描述它超出了这个问题/答案的范围,但绝对可以看一下并在谷歌上搜索一下这个主题。在gnu-make和cc的依赖生成器之间,您可以构建一些非常简单的Makefile,它们会自动为您完成大量的工作。
- 如何在文档文件夹中创建目录
- 如何从Windows控制台调用.exe(C++)以在不同的目录(或任何目录)中创建文件夹?
- 如何使用Windows API C++更改已创建的文件夹/目录安全权限
- 在C++中创建文件夹选取器对话框的最简单方法是什么?
- 在c++编程中的文件夹中创建文件
- 创建文件夹结构
- 在C++中创建文件夹
- 如何使用 c++ 创建对"everyone"具有共享访问权限的文件夹
- 如何在 C++ 中创建一个适用于 Windwos 和 Linux 的文件夹(目录)
- 如果C 中不存在,如何创建文件夹
- 如何将用于创建文件的文件的路径提供给C++中的其他文件夹
- 如何在%appdata%中创建文件夹,在其中创建.bat文件,然后执行它?
- 无法创建将包含日志文件的文件夹
- Windows 7:MFC ActiveX 控件不会在任何文件夹中创建文件
- 嵌入 LuaJIT - 创建包含文件夹
- C - 创建文件夹方法
- 如何在Visual Studio C 2012中创建文件夹
- 如何以编程方式为应用程序创建文件夹,以使用 BOX REST API 在其中上传内容
- 为什么Qt在Qt内部运行时或调试时不会创建文本文件,而是直接从调试文件夹创建文本文件
- 如何从文件文件夹创建自定义文件类型