Cmake vs Make示例代码?


117

我想知道是否有Makefiles(make)和CMakeLists.txtcmake)的示例代码都做相同的事情(唯一的区别是一个写在make另一个中cmake)。

我尝试寻找“ cmake vs make”,但是我从未找到任何代码比较。即使只是简单的情况,了解这些差异也将非常有帮助。


20
+1这是一个好问题;当我刚开始的时候,cmake我也想要这个。但是我怀疑您会找到它,因为这些功能无法将它们很好地映射到另一个。如果您尝试使cmake行为像make,那么您将认真对待自己。最好只是从头开始。琐碎的事情会make涉及很多cmake,反之亦然。
欧内斯特·弗里德曼·希尔

1
@ ErnestFriedman-Hill您是否有更多详细信息?那么,makecmake是如此独特,以至于应该将它们更多地看作是互补的,而不是竞争性的工具?
Ehtesh Choudhury

2
@Shurane-cmake本身并不构建任何东西;它创建Makefile(以及其他类似的构建脚本),然后运行它们。因此,无论何时编写cmake文件,都必须考虑在生成时还是在构建时应应用命令。与cp *.x $(OUTDIR)您在Makefile中编写的“ ” 相比,某些操作(例如,在构建时复制一组通配文件)非常复杂。也许对我来说最烦人的部分是,生成的Makefile完全是设计成不可移植且不灵活的(续)
欧内斯特·弗里德曼·希尔

1
(续)如果不重新运行cmake重新生成Makefile,您甚至不能在同一台计算机上移动源目录!因此,选择不是在cmake和make之间进行,而是在自己编写可移植的Makefile文件或使用cmake在每台构建机上生成不可移植的文件之间进行选择(并且鉴于可以在Windows上使用Cygwin或mingw,我通常发现前者更容易。 )
欧内斯特·弗里德曼·希尔

1
这是一个很好的问题,但没有具体答案,因为这两种工具都试图解决另一个问题。cmake获取有关如何生成程序的信息,生成用于生成程序的makefile。因此,cmake是一种具有抽象构建规则的语言,而gnu make是一种依赖关系解析,可以在有向无环图遍历上执行程序。
亚历克斯

Answers:


118

下面的Makefile会prog从源代码 构建一个名为的可执行文件prog1.c, prog2.c, prog3.c and main.cprog与之相关,libmystatlib.a 并且libmydynlib.so两者也都是从源构建的。此外,prog使用该库libstuff.astuff/lib,并在其头部stuff/include。默认情况下,Makefile构建一个发布目标,但也提供一个调试目标:

#Makefile    
CC = gcc
CPP = g++
RANLIB = ar rcs
RELEASE = -c -O3 
DEBUG = -c -g -D_DEBUG
INCDIR = -I./stuff/include
LIBDIR = -L./stuff/lib -L.
LIBS = -lstuff -lmystatlib -lmydynlib
CFLAGS = $(RELEASE)

PROGOBJS = prog1.o prog2.o prog3.o

prog: main.o $(PROGOBJS) mystatlib mydynlib
    $(CC) main.o $(PROGOBJS) $(LIBDIR) $(LIBS) -o prog 
debug: CFLAGS=$(DEBUG)
debug: prog

mystatlib: mystatlib.o
    $(RANLIB) libmystatlib.a mystatlib.o
mydynlib: mydynlib.o
    $(CPP) -shared mydynlib.o -o libmydynlib.so

%.o: %.c
    $(CC) $(CFLAGS) $(INCDIR) $< -o $@ 
%.o: %.cpp
    $(CPP) $(CFLAGS) $(INCDIR) -fPIC  $< -o $@ 

这是一个CMakeLists.txt(几乎)完全相同的东西,带有一些注释来强调与Makefile的相似之处:

#CMakeLists.txt     
cmake_minimum_required(VERSION 2.8)                    # stuff not directly
project(example)                                       # related to building

include_directories(${CMAKE_SOURCE_DIR}/stuff/include) # -I flags for compiler
link_directories(${CMAKE_SOURCE_DIR}/stuff/lib)        # -L flags for linker

set(PROGSRC prog1.c prog2.c prog3.c)                   # define variable 

add_executable(prog main.c ${PROGSRC})                 # define executable target prog, specify sources
target_link_libraries(prog mystatlib mydynlib stuff)   # -l flags for linking prog target

add_library(mystatlib STATIC mystatlib.c)              # define static library target mystatlib, specify sources

add_library(mydynlib SHARED mydynlib.cpp)              # define shared library target mydynlib, specify sources
#extra flags for linking mydynlib
set_target_properties(mydynlib PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 
#alternatively:
#set_target_properties(mydynlib PROPERTIES COMPILE_FLAGS "-fPIC")

在这个简单的示例中,最重要的区别是:

  • CMake可以识别哪种编译器用于哪种源。同样,它为每种类型的目标调用正确的命令序列。因此,有喜欢的命令没有明确的规范$(CC) ...$(RANLIB) ...等等。

  • 处理包含头文件,库等的所有常规编译器/链接器标志都由独立于平台/独立于构建系统的命令代替。

  • 通过将变量设置CMAKE_BUILD_TYPE为“ Debug”或在调用程序时将其传递给CMake 来包含调试标志cmake -DCMAKE_BUILD_TYPE:STRING=Debug

  • CMake还提供了与平台无关的“ -fPIC”标志(通过该POSITION_INDEPENDENT_CODE属性)以及许多其他标志。仍然可以在CMake中以及在Makefile中(通过使用COMPILE_FLAGS 和类似的属性)手动实现更晦涩的设置。当然,当以可移植的方式包含第三方库(如OpenGL)时,CMake确实开始发光。

  • 如果使用Makefile,则构建过程只有一个步骤,即 make在命令行中键入。对于CMake,有两个步骤:首先,您需要设置构建环境(通过键入cmake <source_dir>构建目录或运行某些GUI客户端)。这会根据您选择的构建系统(例如Unixes或VC ++或Windows上的MinGW + Msys)创建一个Makefile或类似的文件。可以将构建系统作为参数传递给CMake。但是,CMake会根据您的系统配置做出合理的默认选择。其次,您在选定的构建系统中执行实际构建。

源代码和构建说明可从https://github.com/rhoelzel/make_cmake获得


3
Makefile难道不是太复杂吗?如果使用CPPFLAGS而不是INCDIR使用内置规则,则显式调用编译器将是多余的。同样,对于ar的处理,内置规则也可以解决。另外,为什么要设置CPPCC显式?它们已经通过设置为良好的值make,它们是预定义的变量。make还可以识别用于哪种源的编译器,内置规则很多。
Christian Hujer,2015年

1
而且这些变量中的许多变量应该用:=代替=
Christian Hujer,2015年

1
看一下描述,比cmake更具可比性。automakemake
ivan_pozdeev

提供的Makefile可以减少到3/4行。您应指定INCLUDES而不是INCDIR。您不需要%.o:%。c规则。
舒瓦

6

取得一些使用CMake作为其构建系统的软件(例如,有很多开源项目可供选择)。获取源代码并使用CMake对其进行配置。阅读生成的makefile并享受。

要记住的一件事是,这些工具并非一对一映射。最明显的区别是CMake会扫描不同文件(例如C头文件和源文件)之间的依赖关系,而make会将其留给makefile作者。


4

如果此问题MakefileCMakeList.txt文件的示例输出有关,请检查cmake后端源并生成一个这样的源Makefile。如果不是的话,那么我会在@Roberto的回复中添加隐藏详细信息,以使其变得简单。

CMake功能

虽然Make是用于规则和配方的灵活工具,但它CMake是抽象层,还添加了配置功能。

我的平原CMakeLists.txt将如下所示,

cmake_minimum_required(VERSION 2.8)
project(example)
file(GLOB testapp_SOURCES *.cc)
add_executable(testapp ${testapp_SOURCES})

注意,CMake隐藏how构建即可完成。我们只指定what输入和输出。

CMakeLists.txt由定义的函数调用的包含列表cmake

(CMake功能)与制作规则

Makefilerules and recipes被用来代替functions。除了function-like功能,还rules and recipes提供链接。我的简约风格Makefile如下所示,

-include "executable.mk"
TARGETS=testapp.bin
all:${TARGETS}

虽然executable.mk将如下所示,

SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
DEPS=$(SOURCES:.cpp=.d)

%.bin:$(OBJECTS)
    $(CC) $(CFLAGS) -o $@ $^ $(LFLAGS) $(LIBS)

.PHONY: all clean

clean:
    $(RM) $(OBJECTS) $(DEPS) $(TARGETS)

-include $(DEPS)

从头开始,我将从Makefile以下内容开始,

all: testapp.bin

testapp.bin:sourcea.o sourcb.o
    $(CC) $(CFLAGS) -o $@ $^ $(LFLAGS) $(LIBS)

.PHONY: all clean

clean:
    $(RM) $(OBJECTS) testapp.bin

我从这里得到了这个片段并对其进行了修改。请注意,一些隐式规则已添加到此文件中,这些规则可以在makefile文档中找到。一些隐式变量在这里也很重要。

注意,这Makefile提供了recipe显示how可以完成构建的详细信息。可以编写executable.mk以将详细信息保留在一个文件中。这样,可以减少makefile,如我之前所示。

在内部变量CMakeMake

现在变得有点高级了,CMake我们可以像下面这样设置一个编译器标志,

set(CMAKE_C_FLAGS "-Wall")

CMakeCMakeCache.txt文件中找到有关默认变量的更多信息。CMake上面的代码将等同于Make下面的代码,

CFLAGS = -Wall

请注意,CFLAGS中的内部变量Make同样CMAKE_C_FLAGS是中的内部变量CMake

在CMake中添加包含和库路径

我们可以cmake使用函数来做到这一点。

target_include_directories(testapp PRIVATE "myincludes")
list(APPEND testapp_LIBRARIES
    mytest mylibrarypath
)
target_link_libraries(testapp ${testapp_LIBRARIES})

与在Make中添加包含和库路径

我们可以通过添加如下行来添加包含和库,

INCLUDES += -Imyincludes
LIBS += -Lmylibrarypath -lmytest

请注意,以上这些行可以从自动生成工具或pkg-config生成。(尽管Makefile不依赖于自动配置工具)

CMake配置/周

通常,可以通过使用函数来生成一些config.h文件,就像auto-config工具一样configure_file。编写自定义函数可以做更多的技巧。最后我们可以选择如下配置

cmake --build . --config "Release"

使用该option功能可以添加一些可配置的选项。

Makefile配置/调整

如果我们需要以某种调试标志对其进行编译,则可以调用makelike,

make CXXFLAGS=NDEBUG

我认为,内部变量,Makefile-rulesCMake-functions有良好的开端为比较,好运与更多的挖掘。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.