我想知道是否有任何 Makefile(make)和 CMakeLists.txt(cmake)的样本代码都做同样的事情(唯一的区别是一个是用 make写的,另一个是用 cmake写的)。
Makefile
make
CMakeLists.txt
cmake
我尝试查找“ cmake vs make”,但是没有找到任何代码比较。即使只是为了一个简单的案例,理解它们之间的区别也是非常有帮助的。
抓住一些使用 CMake 作为构建系统的软件(有很多开源项目可供选择作为示例)。获取源代码并使用 CMake 对其进行配置。阅读生成的 makefile 并享受其中的乐趣。
需要记住的一点是,这些工具不会一对一地映射。最明显的区别是 CMake 扫描不同文件(例如 C 头文件和源文件)之间的依赖关系,而 make 将这个任务留给 makefile 作者。
下面的 Makefile 从源代码生成一个名为 prog的可执行文件 prog与 libmystatlib.a相连 和 libmydynlib.so都是从源代码构建的。此外,prog使用 stuff/lib中的库 libstuff.a和 stuff/include中的标头 Makefile 默认构建一个发布目标,但也提供一个调试目标:
prog
libmystatlib.a
libmydynlib.so
stuff/lib
libstuff.a
stuff/include
#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) ...等命令的明确规范。
$(CC) ...
$(RANLIB) ...
所有常见的编译器/链接器标志处理包含头文件、库等。 被独立于平台/构建系统的命令所取代。
通过将变量 CMAKE_BUILD_TYPE设置为“ Debug”,可以包含调试标志, 或者在调用程序时将其传递给 CMake: cmake -DCMAKE_BUILD_TYPE:STRING=Debug。
CMAKE_BUILD_TYPE
cmake -DCMAKE_BUILD_TYPE:STRING=Debug
CMake 还提供了独立于平台的“-fPIC”标志(通过 POSITION_INDEPENDENT_CODE财产)和许多其他财产。尽管如此,在 CMake 中可以手工实现更多模糊的设置,就像在 Makefile 中一样(通过使用 COMPILE_FLAGS) 当然,CMake 在第三方时真正开始发光发亮 库(如 OpenGL)是以可移植的方式包含的。
POSITION_INDEPENDENT_CODE
COMPILE_FLAGS
如果使用 Makefile,则构建过程只有一个步骤,即在命令行中键入 make。对于 CMake,有两个步骤: 首先,您需要设置您的构建环境(要么在构建目录中键入 cmake <source_dir>,要么运行一些 GUI 客户端)。这会创建一个 Makefile 或者类似的东西,这取决于你所选择的构建系统(例如 Unixes 上的 make 或者 VC + + 或者 Windows 上的 MinGW + Msys)。构建系统可以作为参数传递给 CMake; 但是,CMake 会根据系统配置做出合理的默认选择。其次,在选定的生成系统中执行实际的生成。
cmake <source_dir>
源代码和构建说明可在 https://github.com/rhoelzel/make_cmake获得。
如果这个问题是关于 CMakeList.txt文件的样例 Makefile输出,那么请检查 cmake-backend 源代码并生成这样的 Makefile。如果这不是然后添加到@罗伯托的回复,我试图通过隐藏的细节使它简单。
CMakeList.txt
虽然 Make是用于规则和菜谱的灵活工具,但 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是输入和输出。
how
what
CMakeLists.txt包含由 cmake定义的函数调用列表。
在 Makefile中使用的是 rules and recipes而不是 functions。除了类似 function的功能,rules and recipes还提供链接。我的简约 Makefile会像下面这样,
rules and recipes
functions
function
-include "executable.mk" TARGETS=testapp.bin all:${TARGETS}
虽然 executable.mk看起来如下所示,
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-document 中找到。一些隐式变量在这里也是相关的。
注意,Makefile提供了显示构建可以完成的 how的详细信息 recipe。可以编写 executable.mk来保持在一个文件中定义的详细信息。这样,makefile 就可以像我前面展示的那样减少。
recipe
现在稍微进一步,在 CMake中我们可以像下面这样设置一个编译器标志,
set(CMAKE_C_FLAGS "-Wall")
请在 CMakeCache.txt文件中找到更多关于 CMake默认变量的信息。 上面的 CMake代码相当于下面的 Make代码,
CMakeCache.txt
CFLAGS = -Wall
请注意,CFLAGS是 Make中的一个内部变量,同样地,CMAKE_C_FLAGS是 CMake中的一个内部变量。
CFLAGS
CMAKE_C_FLAGS
我们可以使用函数在 cmake中完成。
target_include_directories(testapp PRIVATE "myincludes") list(APPEND testapp_LIBRARIES mytest mylibrarypath ) target_link_libraries(testapp ${testapp_LIBRARIES})
我们可以通过添加以下代码行来添加包含和库,
INCLUDES += -Imyincludes LIBS += -Lmylibrarypath -lmytest
注意,上面的代码行可以从 auto-gen 工具或 pkg-config 生成(尽管 Makefile 不依赖于 auto-config 工具)
通常可以使用 configure_file函数生成一些类似于 auto-config工具的 config.h文件。编写自定义函数可能需要更多技巧。最后我们可以像下面这样选择一个配置,
configure_file
auto-config
config.h
cmake --build . --config "Release"
可以使用 option函数添加一些可配置选项。
option
如果我们需要用一些调试标志来编译它,我们可以调用 make,
make CXXFLAGS=NDEBUG
我认为内部变量 Makefile-rules和 CMake-functions是比较的良好开端,祝你好运,继续挖掘。
Makefile-rules
CMake-functions