我正在将一个 C++ 项目从 Windows 迁移到 Linux,现在需要创建一个构建/make 文件。我以前从未创建过构建/生成文件。我还需要包含 Boost 库以使其更加复杂。 它也必须是一个 makefile,无论如何我都需要学习如何创建 makefile,所以 CMake 和 SCON 已经淘汰了。由于使用了 Boost,IDE 也被淘汰了,我所有的 IDE(Eclipse、VS 等)都只能在 Windows 上运行。我必须从头开始生成一个 makefile。
那么创建 Linux c++ make 文件的基础知识是什么以及如何将 Boost 库合并到其中以使其正确链接?
到目前为止,我的 makefile 看起来像这样。我认为 CFLAGS 和 LDFLAGS 是编译器和优化选项,但不完全确定。
CC = g++
CFLAGS = -wall -o3 - c
LDFLAGS = -03 -mfp-rounding-mode=n
我提供赏金,因为我仍然很迷失。如果有人喜欢冒险,我需要在 linux
- simple_ls.h
- simple_ls.cpp
- 2dquicksort.h
- rawr.h
- rawr.cpp
- converter.cpp
中编译以下内容 simple_ls.h 中的标头:
#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"
#include "boost/lexical_cast.hpp"
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
2dquicksort.h 中的标头: 2dquicksort.h
#include <stdio.h>
#include <ctype.h>
#include <iostream>
中的标头 : rawr.h:
#include <iostream> // not required by most systems
#include <fstream>
#include <iomanip>
#include <cstdlib> // or (stdlib.h) for exit()
#include <cmath>
#include <vector>
#include <limits>
#include <string>
一个可接受的答案是逐步解释 makefile 如何工作以及如何在没有 IDE 的 Linux 中使用 Boost 构建它们。
I am moving a C++ project from Windows to Linux and I now need to create a build/make file. I have never created a build/make file before. I also need to include Boost libraries to make it more complicated. It must also be a makefile and I need to learn how to create makefile anyway, so CMake and SCON are out. IDEs are also out because of the use of Boost and all my IDEs (Eclipse, VS, etc.) are only on windows. I must generate a makefile from scratch.
So what are the basics of creating a Linux c++ make file and how to incorporate the Boost libraries in it to have it properly link?
So far, my makefile looks like this. I think CFLAGS
and LDFLAGS
are compiler and optimization options, but not totally sure.
CC = g++
CFLAGS = -wall -o3 - c
LDFLAGS = -03 -mfp-rounding-mode=n
I am offering a bounty because I am still very lost. In case anyone is feeling adventurous, I need to compile the following in linux
- simple_ls.h
- simple_ls.cpp
- 2dquicksort.h
- rawr.h
- rawr.cpp
- converter.cpp
The headers in simple_ls.h:
#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"
#include "boost/lexical_cast.hpp"
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
The headers in 2dquicksort.h:
#include <stdio.h>
#include <ctype.h>
#include <iostream>
The headers in rawr.h:
#include <iostream> // not required by most systems
#include <fstream>
#include <iomanip>
#include <cstdlib> // or (stdlib.h) for exit()
#include <cmath>
#include <vector>
#include <limits>
#include <string>
An acceptable answer would be a step-by-step explanation of how makefiles work and how to build them with Boost in Linux without an IDE.
发布评论
评论(10)
什么是Makefile? (应用于 Boost 项目)
根递归 Makefile 背后的想法是:
先决条件
它们是文件、文件夹或假目标(通常在
.PHONY)。测试文件/文件夹的存在性和修改日期。
如果目标没有先决条件或者比任何先决条件都旧,则需要重建目标。
指令
指令是shell 命令,从一个选项卡开始。每条指令行都是一个 shell 实例。当当前命令以反斜杠
\
结尾时,shell 命令可以在下一行继续。目标定义
目标可以是依赖项,也可以是规则。
依赖性:
规则:
指令开始前有制表符。
调试
Makefile 的调试可能会变得非常令人头疼。
请尝试在 Makefile 中执行以下操作来显示跟踪(包含警告的文件和行位置):
当您的 Makefile 包含大量嵌套的
if/else/endif
并且您不确定现在的路径是什么?
Makefile 结构
理想的 makefile 结构是:
一旦整个 Makefile 及其包含文件完成,真正的目标指令处理就会开始
已被理解(存储在
make
内部数据库中)。示例
最后,使用 Boost 将理论应用到这个特定示例并创建假源文件
来说明。
rawr.cpp
simple_ls.cpp
converter.cpp
Makefile
如果您从 *stack***overflow** 复制
Makefile
源,请不要忘记用真正的制表符替换空格:Makefile 源:
文件列表
编译
结果
和现在,几乎最小的 Boost 程序的结果:
没有理由不使用它! Boost 确实是一个特色 C++ 工具箱:)
What is a Makefile ? (applied to a Boost project)
The root recursive idea behind Makefile is:
Prerequisites
They are either files, folders or fake targets (usually in
.PHONY
). Files/folders are tested for existence and modification date.The target needs to be rebuilt if it has no prerequisite or if older that any of the prerequisites.
Instruction
An Instruction is shell commands, starting with one tab. Each instruction line is one shell instance. The shell command can be continued on next line when the current one ends with backslash
\
.Target definition
A target is either a dependency or a rule.
Dependency:
Rule:
With tabs in front of instruction start.
Debug
Debugging a Makefile can become a real headache.
Try the following in your Makefile to show traces (with file and line location for
warning
):This is helpful when your Makefile contains lots of nested
if/else/endif
and you're not sureanymore what is the current path.
Makefile Structure
The ideal makefile structure is:
The real target-instructions processing starts once the whole Makefile and its include files
has been understood (stored in
make
internal database).Example
Finally, apply theory to this specific example using Boost and create fake source files
to illustrate.
rawr.cpp
simple_ls.cpp
converter.cpp
Makefile
Don't forget to replace spaces with real Tabs if you copy
Makefile
source from *stack***overflow** :Makefile source:
File list
Compilation
Result
And now, the result of nearly the tiniest Boost program:
No excuse not to use it ! Boost is really a featured C++ toolbox :)
一个非常简单的 GNU makefile 如下:
CPPFLAGS
是应用于 C 预处理器的标志。诸如包含路径之类的东西。CXXFLAGS
是应用于 C++ 编译器的标志。诸如优化级别之类的事情。LDFLAGS
是应用于链接器的标志。诸如外部库(boost_filesystem)和其他库之类的东西。另外,还有这些库的路径。make all
规则,这是默认规则。在 make 中,第一条规则是默认的。binary_name
是二进制文件的名称。binary_name
取决于 3 个文件:foo.o
、bar.o
、john.o
。*.o
的规则,因为 gnu make 对这些规则有隐式规则。要使用 make,您需要创建一个名为
Makefile
的文件,其中包含上面列出的内容。要构建,您需要在该目录中运行make
。顺便说一句(正如其他人提到的),我建议如果可能的话,不要使用 make。那里有更好的系统。 make 的主要好处是它无处不在。然而,如果管理层需要它,那么管理层就需要它。
(请注意,GNU Make
+=
表示法并不总是可移植到其他版本的 Make。但是,Linux 上的make
是 GNU Make。)根据您的编辑,这里有一个示例与您记下的文件。需要注意的是,以 $(CXX) 开头的行应该以 TAB 字符开头!
A very simple GNU makefile follows:
CPPFLAGS
are flags that are applied to the C Preprocessor. Things like include paths.CXXFLAGS
are flags that are applied to the C++ compiler. Things like optimization levels.LDFLAGS
are flags that applied to the linker. Things like external libraries (boost_filesystem) and other libraries. Also, the paths to those libraries.make all
rule, which is the default. In make, the first rule is the default.binary_name
is the name of your binary.binary_name
depends on 3 files:foo.o
,bar.o
,john.o
.*.o
because gnu make has an implicit rule for those.To use make, you would create a file named
Makefile
with the contents listed above. To build, you would runmake
in that directory.As an aside (and as others have mentioned), I would recommend moving away from make if possible. There are better systems out there. The main benefit of make is that it's everywhere. However, if management requires it, then management requires it.
(Note that the GNU Make
+=
notation is not always portable to other versions of Make. However,make
on Linux is GNU Make.)Given your edit, here's an example with the files that you note. The one caution is that the line beginning with $(CXX) should begin with a TAB character!
我不建议编写您自己的
Makefile
。相反,请使用 CMake 或 SCons.值得注意的是,这些工具是跨平台的。因此您可以在 Linux 和 Windows 上使用相同的构建系统。
I would not recommend writing your own
Makefile
s. Instead, use a build system like CMake or SCons.It is worth noting that those tools are cross-platform. So you can use the same build system on Linux and Windows.
当然,您应该阅读 The Fine Manual(特别是 gcc 和 make)。不过,以下是 gcc 的基础知识:
编译源文件:
这将创建 file.o。然后您可能想要链接它们:
这将创建一个名为app_name的可执行文件。但由于您使用的是 boost 并且头文件可能遍布各处,因此您可能需要其他选项。在编译期间使用 -I 将目录添加到包含路径:
您可能还需要链接到一些库。链接期间:
现在进入 makefile。 makefile 的基础知识是:
例如:
如果您键入“make”,它将默认尝试创建第一个目标。 my_app 依赖于目标 file.o,因此它将检查自上次修改 my_app 以来 file.o 是否已被修改。如果是这样,它将重新链接。在检查 file.o 时,它注意到 file.o 依赖于 file.cpp 和 file.h。如果自上次创建 file.o 以来这些文件中的任何一个已被修改,它将重新编译该文件。
目标也不必总是实际文件。最后一个称为 clean,它不依赖任何东西,只是删除 file.o 和 my_app。如果您输入“make clean”,它将运行该命令。
当然还有很多其他选择,但这应该可以帮助您入门。
Of course you should Read The Fine Manual (specifically gcc and make). However, here are the basics for gcc:
To compile a source file:
This will create file.o. Then you'll probably want to link them:
This will create an executable called app_name. But since you are using boost and might have header files located all over the place, you'll probably need additional options. Use -I during the compilation to add a directory to the include path:
You'll probably also need to link to some libraries. During linking:
Now onto makefiles. The basics of a makefile are:
For example:
If you type 'make' it will be default try to create the first target. my_app depends on the target file.o, so it will check to see if file.o has been modified since the last time my_app has been modified. If so, it will relink. In checking file.o, it notices that file.o depends on file.cpp and file.h. If either of those files have been modified since the last time file.o was created, it will recompile that file.
Targets don't always have to be actual files either. The last one is called clean, it doesn't depend on anything and just deletes file.o and my_app. If you type 'make clean' it will run the command.
There are of course a ton of other options, but that should get you started.
至少尝试阅读您要使用的产品的官方文档: 这里。它确实解释了几乎所有的基础知识。
特别是,阅读第 2 章和第 3 章,这些将使您 99% 达到有效使用 gmake 所需的程度。此外,请仔细阅读 隐式规则目录。这将告诉您大多数“特殊变量”是什么。
我给您的一个提示是在您的项目目录中尝试
gcc -M *.cpp
。这将以 Makefile 格式输出每个 .cpp 文件的先决条件标头列表。事实上,对于初学者 makefile,您可以这样做:编辑此文件,或多或少地在前面添加 shath 的答案,然后您就拥有了一个可用的 Makefile。我可能会建议您删除 gcc -M 将添加到每个构建规则中的大量系统标头,但您实际上不必这样做。
FWIW,如果您开始处理一个大型项目(多个源目录是一个很好的线索),那么是时候开发一种现代构建管理工具(这里是 cmake 粉丝)。但对于小型项目来说,raw make 非常容易使用。
At least try to read through the official documentation of the product you're trying to use: here. It does explain nearly all of the basics.
In particular, read chapters 2 and 3, those will get you 99% of the way to where you need to be to use gmake effectively. In addition, carefully read the Catalogue of Implicit Rules. This will tell you what most of those "special variables" are.
One hint I'd give you is to try out
gcc -M *.cpp
in your project directory. This will output a list of prerequisite headers for each of your .cpp files in Makefile format. In fact, for a starter makefile, you can just do:Edit this file, more or less prepending sharth's answer to it, and you have a workable Makefile. I would probably advise you remove the large number of system headers that gcc -M is going to add to each build rule, but you don't really have to.
FWIW, if you start working on a large project (more than one source directory is a good clue), it's time to break out a modern build management tool (cmake fan here). But for small projects, raw make is pretty easy to use.
这并不完全是您所要求的,但我强烈建议您使用名为 premake 的构建系统。 premake 和 scons 以及 cmake 之间的好处和区别是它为您生成 makefile。这意味着您可以使用 premake 作为开始,然后查看它生成的文件以了解更多信息。
除了这个预制件之外,它还是一个易于学习且直观的工具,它还有一个额外的好处,即能够从相同的配置生成 Visual Studio 项目文件。
我的建议是,如果您绝对需要 makefile,则使用 premake,它将帮助您学习,并最终成为直接编写自己的 makefile 的灵活替代品(这是一个主要的痛苦是 %*$)。
It's not exactly what you were requesting but I would highly recommend that you use a build system called premake. The benefit, and difference, between premake and scons and cmake is that it generates makefiles for you. This means that you can use premake as a start and then look at the files it generates to learn more.
Aside from this premake is an easy to learn and intuitive tool and it has the added benefit of being able to generate visual studio project files from the same configuration.
My advice would be to use premake if you absolutely have to have makefiles, it will help you learn and is ultimately a flexible replacement for directly writing your own makefiles (which is a major pain is the %*$).
有一个非常好的教程@ ALP 。
There is a very good tutorial @ ALP.
首先,我不是 Makefile 方面的专家。我知道基础知识,但是这个答案中的 Makefile 几乎肯定有改进的空间。有很多技巧和快捷方式可以让您比硬编码所有内容更好地处理依赖项和添加文件。不过,我认为这个例子足以满足您的目的,并且可能更具教育意义。
其次,我想确保您了解构建项目的基本阶段。您可能已经知道这一点,但如果您不知道,下面的内容一开始会有点混乱。本质上有两个步骤:编译和链接。编译会将您的代码转换为目标代码 - 如果成功,它将把 .cpp 文件转换为 .o 文件。下一步是链接。在这里,它将所有目标代码粘在一起以创建可执行文件,并将函数调用从一个文件链接到另一个文件(因此,如果 file1.cpp 调用 file2.cpp 中定义的函数,则在这一步file1.cpp 找出该函数的实际位置)。还有更多内容,但这应该足以阐明以下内容。
此时,您可以使用
g++
来编译和链接您的项目(您甚至可以“一步”完成)。然而,这是相当麻烦的,尤其是对于任何重要的项目。它还使得跟踪自上次编译以来已更改的文件变得困难。这就是 Makefile 的用武之地。 Makefile 是以下形式的规则列表:(
确保使用制表符而不是空格,如果使用空格,make 可能无法工作)。如果运行命令:
那么 make 将查找带有
some_target
的规则。如果目标是一个文件,它将检查该文件的“上次修改”时间戳,并将检查您列出的所有依赖项的时间戳。如果任何依赖项具有较晚的时间戳,它将运行该命令。我将不得不对您的项目做出一些假设(即哪些文件依赖于哪些文件),因此您可能需要修改以下内容,但这是您项目的基本 Makefile(请记住,制表符而不是空格。如果您复制并粘贴此内容,它将不起作用):
运行
make
或make all
或make binary_file
将导致编译所有文件如有必要,然后链接以创建名为binary_file
的可执行文件。您可以进行一些改进,例如:它将找到所有 .cpp 文件并将它们编译为 .o 文件。 .o 文件将依赖于同名的 .cpp 文件和 .h 文件(以及 2dquicksort.h)。
First off, I am not an expert on Makefiles. I know the basics, but the Makefile in this answer will almost certainly have room for improvement. There are a lot of tricks and shortcuts that will allow you to handle dependencies and adding files better than hardcoding everything. However I think this example will be sufficient for your purposes and will possibly be more educational.
Second, I want to make sure you know the basic stages of building a project. You may already know this, but if you don't the following will be a bit confusing at first. There are essentially two steps: compiling and linking. Compiling converts your code to object code - it will convert a .cpp file to a .o file if successful. The next step is linking. This is where it sticks all the object code together to create an executable and links the function calls from one file to another (so if file1.cpp calls a function defined in file2.cpp, it's at this step that the file1.cpp figures out where the function actually is). There is more to it but that should be enough to make the following clear.
At this point you can just use
g++
to compile and link your project (you can even do it in "one" step). This is quite cumbersome however, especially for any non-trivial project. It also makes it difficult to track files that have changed since you last compiled.This is where Makefiles come in. A Makefile is a list of rules in the form:
(Make sure to use tabs not spaces, make probably won't work if you use spaces). If you run the command:
Then make will look for the rule with
some_target
. If the target is a file, it will check the 'last modified' time stamp of the file, and it will check the time stamps of all the dependencies you have listed. If any of the dependencies have a later time stamp, it will run the command.I'm going to have to make some assumptions about your project (namely, which files depend on which files) so you will probably have to modify the following, but here is a basic Makefile for your project (and remember, tabs not spaces. If you copy and paste this it won't work):
Running
make
ormake all
ormake binary_file
will cause all your files to be compiled if necessary and then linked to create an executable calledbinary_file
. There are some improvements you can make, for example:Which will find all the .cpp files and compile them in to .o files. The .o files will be dependent on a .cpp file and a .h file of the same name (and 2dquicksort.h).
使用 @Job 的想法,我建议您将其留给某些 IDE 来完成。例如,在 Eclipse CDT 中构建一个项目并使用它自动生成的 make 文件。然后,您可以学习它,并及时更改它以完全满足您的需求。
Using @Job 's idea, I recommend you to leave it for some IDE to do. For example, Build a project in Eclipse CDT and use it's auto-generated make file. Then, you can kearn it and by the time change it to fit exactly your needs.
我更喜欢标准的项目描述,例如这个。换句话说,我认为对 makefile 的关注范围太窄了。
该项目描述的优点是简单。它可以使用
all
目标中的make -C subdir -f Makefile all
来适应带有子目录的更复杂的项目。subdir
当然是您的子目录,其中包含应构建的代码。作者指出,创建和维护构建环境效率不高,因此您需要易于修改且易于理解的东西。我不一定想成为一名 makefile 专家。我认为这并不像许多人想象的那么有用。
我非常喜欢 hiltmon 的想法,所以我将它变成了 shell 脚本。我可能会用Python编写完成的项目,并询问作者是否可以为GitHub做出贡献。
I prefer a standard project description such as this one. In other words, I believe the focus on a makefile is too narrow.
The virtue of this project description is simplicity. It can be adapted to more complex projects with sub-directories using
make -C subdir -f Makefile all
in anall
target. Thesubdir
is of course your sub-directory with code that should be built.The author points out that creating and maintaining build environments are not productive, so you want something that is easy to modify and that you understand. I would not necessarily set out to be a makefile expert. I don't think that's as useful as many think.
I like hiltmon's idea so much I'm turning it into a shell script. I may write the finished project in Python and ask the author if I can contribute to GitHub.