创buildLinux make / build文件

我将一个C ++项目从Windows移到Linux,现在我需要创build一个build / make文件。 我以前从来没有创build过构build/制作文件。 我还需要包含Boost库以使其更加复杂。 它也必须是一个makefile,我需要学习如何创buildmakefile,所以CMake和SCON都不在了。 由于Boost的使用,IDE也出来了,我所有的IDE(Eclipse,VS等)都只能在windows上运行。 我必须从头开始生成一个makefile。

那么创build一个Linux c ++ make文件的基础是什么,以及如何将Boost库合并到一起以便正确链接?

到目前为止,我的makefile看起来像这样。 我认为CFLAGSLDFLAGS是编译器和优化选项,但不完全确定。

 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中的头文件:

 #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的情况下用Boost在Linux中构build它们。

什么是Makefile(应用于Boost项目)

Makefile背后的根本递归思想是:

要构建目标,我们需要先决条件 (其他目标!)和指令来构建

先决条件

他们是文件,文件夹或假目标(通常在.PHONY )。 文件/文件夹被测试的存在和修改日期。

目标需要重建,如果没有先决条件或任何先决条件。

指令

一个指令是shell命令 ,从一个选项卡开始。 每个指令行是一个shell实例。 当前的命令以反斜杠\结尾时,shell命令可以在下一行继续。

目标定义

目标是依赖项规则

相关性:

 target : prerequisite1 prerequisite2 prerequisiteN 

规则:

 target : prerequisite1 prerequisite2 prerequisiteN instructions1 @hidden_batch1 ; \ hidden_batch2 

在指令开始前带有标签。

调试

调试一个Makefile可能会成为一个令人头痛的问题。 在您的Makefile中尝试以下内容以显示跟踪(包含warning文件和行位置):

 $(info Shell: $(SHELL)) $(warning CXX: $(CXX)) 

当你的Makefile包含很多嵌套的if/else/endif时,这是有帮助的,而且你不再确定当前的路径是什么。

Makefile结构

理想的makefile结构是:

  1. 可变设置
  2. 目标/依赖声明

一旦整个Makefile及其包含文件被理解(存储在make内部数据库中),真正的目标指令处理就开始了。

最后,使用Boost将理论应用于这个特定的例子,并创建伪造的源文件来说明。

rawr.cpp

 #include "rawr.h" 

simple_ls.cpp

 #include "rawr.h" 

converter.cpp

 #include <iostream> #include "rawr.h" #include "simple_ls.h" #include "2dquicksort.h" #include <boost/array.hpp> // Boost! int main(int argc, char **argv) { boost::array<int,4> a = { { 1, 2, 3, 4} }; std::cout << a[1] << std::endl; return 0; } 

Makefile文件

如果从* stack *** overflow复制Makefile源代码,请不要忘记用真正的Tabs替换空格**:

 sed -i~ -e 's/^ /\t/' Makefile 

Makefile源码:

 ## Makefile for C++ project using Boost # # @author Cedric "levif" Le Dillau # # Some notes: # - Using ':=' instead of '=' assign the value at Makefile parsing time, # others are evaluated at usage time. This discards # - Use ':set list' in Vi/Vim to show tabs (Ctrl-vi force tab insertion) # # List to '.PHONY' all fake targets, those that are neither files nor folders. # "all" and "clean" are good candidates. .PHONY: all, clean # Define the final program name PROGNAME := converter # Pre-processor flags to be used for includes (-I) and defines (-D) CPPFLAGS := -DUSE_BOOST # CFLAGS is used for C compilation options. CFLAGS := -Wall -O0 # CXXFLAGS is used for C++ compilation options. CXXFLAGS += -Wall -O0 # LDFLAGS is used for linker (-g enables debug symbols) LDFLAGS += -g # Which Boost modules to use (all) BOOST_MODULES = \ date_time \ filesystem \ graph \ iostreams \ math_c99 \ system \ serialization \ regex # Boost libraries' type (a suffix) BOOST_MODULES_TYPE := -mt # Define library names with their type BOOST_MODULES_LIBS := $(addsuffix $(BOOT_MODULES_TYPE),$(BOOST_MODULES)) # Define the linker argument to use the Boost libraries. BOOST_LDFLAGS := $(addprefix -lboost_,$(BOOST_MODULES_LIBS)) # Feed compiler/linker flags with Boost's CPPFLAGS += $(BOOST_CPPFLAGS) LDFLAGS += $(BOOST_LDFLAGS) # List the project' sources to compile or let the Makefile recognize # them for you using 'wildcard' function. # #SOURCES = simple_ls.cpp rawr.cpp converter.cpp SOURCES = $(wildcard *.cpp) # List the project' headers or let the Makefile recognize # them for you using 'wildcard' function. # #HEADERS = simple_ls.h 2dquicksort.h rawr.h HEADERS = $(wildcard %.h) # Construct the list of object files based on source files using # simple extension substitution. OBJECTS = $(SOURCES:%.cpp=%.o) # # Now declare the dependencies rules and targets # # Starting with 'all' make it becomes the default target when none # is specified on 'make' command line. all : $(PROGNAME) # Declare that the final program depends on all objects and the Makfile $(PROGNAME) : $(OBJECTS) Makefile $(CXX) -o $@ $(LDFLAGS) $(OBJECTS) # Now the choice of using implicit rules or not (my choice)... # # Choice 1: use implicit rules and then we only need to add some dependencies # to each object. # ## Tells make that each object file depends on all headers and this Makefile. #$(OBJECTS) : $(HEADERS) Makefile # # Choice 2: don't use implicit rules and specify our will %.o: %.cpp $(HEADERS) Makefile $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $(OUTPUT_OPTION) $< # Simple clean-up target # notes: # - the '@' before 'echo' informs make to hide command invocation. # - the '-' before 'rm' command to informs make to ignore errors. clean : @echo "Clean." -rm -f *.o $(PROGNAME) 

文件列表

 2dquicksort.h converter.cpp Makefile rawr.cpp rawr.h simple_ls.cpp simple_ls.h 

汇编

 make clean all Clean. rm -f *.o converter g++ -Wall -O0 -DUSE_BOOST -c -o converter.o converter.cpp g++ -Wall -O0 -DUSE_BOOST -c -o rawr.o rawr.cpp g++ -Wall -O0 -DUSE_BOOST -c -o simple_ls.o simple_ls.cpp g++ -o converter -g -lboost_date_time -lboost_filesystem -lboost_graph -lboost_iostreams -lboost_math_c99 -lboost_system -lboost_serialization -lboost_regex converter.o rawr.o simple_ls.o 

结果

而现在,几乎最小的Boost程序的结果:

 ./converter 2 

没有理由不使用它! Boost实际上是一个精选的C ++工具箱:)

一个非常简单的GNU makefile如下:

 CPPFLAGS += -Isome_include_path CXXFLAGS += -O3 LDFLAGS += -Lsome_link_path -lsome_lib -lboost_filesystem all: binary_name binary_name: foo.o bar.o john.o 
  • CPPFLAGS是应用于C预处理器的标志。 像包括路径的东西。
  • CXXFLAGS是应用于C ++编译器的标志。 像优化水平的东西。
  • LDFLAGS是应用于链接器的标志。 像外部库(boost_filesystem)和其他库。 此外,这些库的路径。
  • 公约说,应该有一个make all规则,这是默认的。 在make中,第一个规则是默认的。
  • binary_name是您的二进制文件的名称。
  • binary_name取决于3个文件: foo.ojohn.ojohn.o
  • 我们不包含*.o规则,因为gnu make对这些规则有一个隐含的规则。

要使用make,可以使用上面列出的内容创建一个名为Makefile的文件。 要构建,您可以在该目录中运行make

另外(和其他人一样),如果可能的话,我建议尽量避开。 那里有更好的系统。 make的主要好处是无处不在。 但是,如果管理层要求,那么管理层就需要这样做。

(请注意,GNU Make += notation并不总是可移植到其他版本的Make上,但在Linux上make是GNU Make。)


鉴于你的编辑,这里是你注意到的文件的例子。 一个小心的是,以$(CXX)开头的行应该以TAB字符开头!

 LDFLAGS := -lboost_filesystem CXXFLAGS := -O3 -Wall CPPFLAGS := all: program program: simple_ls.o converter.o rawr.o $(CXX) -o $< $^ $(LDFLAGS) simple_ls.o: simple_ls.cpp rawr.h simple_ls.h 2dquicksort.h converter.o: converter.cpp rawr.h simple_ls.h 2dquicksort.h rawr.o: rawr.cpp rawr.h simple_ls.h 2dquicksort.h 

我不会推荐编写你自己的Makefile 。 相反,使用像CMake或SCons的构建系统。

值得注意的是,这些工具是跨平台的。 所以你可以在Linux和Windows上使用相同的构建系统。

当然你应该阅读精细手册(特别是gcc和make)。 不过,这里是gcc的基础知识:

编译源文件:

 g++ -c file.cpp 

这将创建file.o. 那么你可能想要链接它们:

 g++ -o app_name file.o main.o other_file.o 

这将创建一个名为app_name的可执行文件。 但是既然你使用了boost,而且可能有遍布整个地方的头文件,你可能需要额外的选项。 在编译期间使用-I将目录添加到包含路径中:

 g++ -I/usr/local/more_includes/ -c file.cpp 

你可能还需要链接到一些库。 在连接期间:

 g++ -L/usr/local/more_libraries/ file.o main.o other_file.o -lsome_library 

现在到makefile。 一个makefile的基础是:

 target: dependencies command 

例如:

 my_app: file.o g++ -o my_app file.o file.o: file.cpp file.h g++ -o file.cpp clean: rm file.o my_app 

如果您输入“make”,则默认尝试创建第一个目标。 my_app依赖于目标file.o,所以它会检查自上次my_app被修改以来是否修改了file.o。 如果是这样,它会重新链接。 在检查file.o时,注意到file.o依赖于file.cpp和file.h. 如果自上次创建file.o以来,其中的任何一个文件都被修改过,则会重新编译该文件。

目标并不总是必须是实际的文件。 最后一个被称为干净的,它不依赖于任何东西,只是删除file.o和my_app。 如果你输入'make clean',它将运行命令。

当然还有很多其他的选择,但这应该让你开始。

至少试着通读你正在使用的产品的官方文档: 这里 。 它确实解释了几乎所有的基础知识。

特别是,阅读第2章和第3章,这些将使您有效地使用gmake的99%的途径。 另外,请仔细阅读隐含规则目录 。 这将告诉你这些“特殊变数”是多么的多。

我想给你的一个提示是在你的项目目录下试用gcc -M *.cpp 。 这将以Makefile格式输出每个.cpp文件的必备标题列表。 事实上,对于初学者的makefile,你可以做:

 gcc -M *.cpp > Makefile 

编辑这个文件,或多或少地预先考虑sharth的答案,并且你有一个可行的Makefile。 我可能会建议你删除gcc -M要添加到每个构建规则的大量系统头文件,但是你并不需要。

FWIW,如果你开始在一个大型项目上工作(多个源目录是一个很好的线索),是时候打破现代的建设管理工具(cmake粉丝在这里)。 但是对于小项目来说,原始制作很容易使用。

这不完全是你要求的,但我强烈建议你使用一个名为premake的构建系统。 premake和scons和cmake之间的好处和不同之处在于它会为您生成makefile。 这意味着您可以使用premake作为开始,然后查看它生成的文件以了解更多信息。

除了这个premake是一个易于学习和直观的工具,它还能够从相同的配置生成visual studio项目文件的额外好处。

我的建议是使用预制,如果你绝对必须有makefile,它将帮助你学习,并最终是一个灵活的替代品,直接编写自己的makefile(这是一个主要的痛苦是%* $)。

有一个非常好的教程@ ALP 。

首先,我不是Makefiles的专家。 我知道基础知识,但这个答案中的Makefile几乎肯定会有改进的空间。 有很多的技巧和快捷方式,将允许您处理依赖和添加文件比硬编码更好。 不过,我认为这个例子足以满足你的需求,而且可能会更具教育意义。

其次,我想确保你知道建设一个项目的基本阶段。 你可能已经知道这一点,但是如果你不这样做,以下将会有点混乱。 基本上有两个步骤:编译和链接。 编译将您的代码转换为目标代码 – 如果成功,它会将.cpp文件转换为.o文件。 下一步是链接。 这是所有的目标代码粘在一起创建一个可执行文件,并将函数调用从一个文件链接到另一个文件(因此,如果file1.cpp调用file2.cpp中定义的函数,在这一步file1.cpp算出功能实际上是)。 还有更多的东西,但这应该足以说清楚。

在这一点上,你可以使用g++来编译和链接你的项目(甚至可以在“一步”中完成)。 然而,这非常麻烦,特别是对于任何不平凡的项目。 这也使得跟踪自上次编译以来发生更改的文件变得困难。

这是Makefiles进来的地方。Makefile是一个规则列表,格式如下:

 target: dependencies command 

(确保使用不是空格的制表符,如果使用空格,可能不会起作用)。 如果你运行这个命令:

 make some_target 

然后make会用some_target寻找规则。 如果目标是文件,它将检查文件的“上次修改时间”时间戳,并检查所列出的所有依赖关系的时间戳。 如果任何依赖关系具有较晚的时间戳,则将运行该命令。

我将不得不对你的项目做一些假设(即哪些文件取决于哪些文件),所以你可能需要修改以下内容,但是这里是你的项目的一个基本的Makefile(并且记住,制表符不是空格。如果你复制并粘贴这个将不起作用):

 CC = g++ INCLUDE_DIRS = -I/path/to/boost all: binary_file clean: rm *.o rm binary_file binary_file: simple_ls.o rawr.o converter.o $(CC) -o binary_file simple_ls.o rawr.o converter.o rawr.o: rawr.h rawr.cpp 2dquicksort.h $(CC) -c rawr.cpp $(INCLUDE_DIRS) simple_ls.o: simple_ls.h simple_ls.cpp 2dquicksort.h $(CC) -c simple_ls.cpp $(INC*emphasized text*LUDE_DIRS) 

运行makemake allmake binary_file会导致所有的文件被编译,如果需要的话,然后链接到一个名为binary_file的可执行文件。 您可以进行一些改进,例如:

 %.o: %.cpp %.h 2dquicksort.h $(CC) -c $< 

这将找到所有.cpp文件并将其编译到.o文件中。 .o文件将依赖于.cpp文件和相同名称的.h文件(和2dquicksort.h)。

使用@Job的想法,我建议你把它留给一些IDE来做。 例如,在Eclipse CDT中构建一个项目并使用它的自动生成的make文件。 然后,你可以改变它,以适应你的需要。