我想知道是否有任何用于Makefile
s ( make
) 和CMakeLists.txt
( cmake
) 的示例代码都做同样的事情(唯一的区别是一个写在里面make
,另一个写在里面cmake
)。
我尝试寻找'cmake vs make',但我从未找到任何代码比较。即使只是一个简单的案例,理解这些差异也会很有帮助。
以下 Makefile 构建了一个以prog
源
命名的可执行文件prog1.c, prog2.c, prog3.c and main.c
。prog
链接到libmystatlib.a
并且libmydynlib.so
它们都是从源代码构建的。此外,使用in 中prog
的库及其在. Makefile 默认构建一个发布目标,但也提供一个调试目标:libstuff.a
stuff/lib
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) ...
。
所有处理包含头文件、库等的常用编译器/链接器标志都被平台独立/构建系统独立命令所取代。
通过将变量设置CMAKE_BUILD_TYPE
为“调试”或在调用程序时将其传递给 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 客户端)。这将创建一个 Makefile 或类似的东西,具体取决于您选择的构建系统(例如,Unix 上的 make 或 VC++ 或 Windows 上的 MinGW + Msys)。构建系统可以作为参数传递给 CMake;但是,CMake 会根据您的系统配置做出合理的默认选择。其次,您在选定的构建系统中执行实际构建。
源代码和构建说明可在https://github.com/rhoelzel/make_cmake获得。
获取一些使用 CMake 作为其构建系统的软件(作为示例,有很多开源项目可供选择)。获取源代码并使用 CMake 进行配置。阅读生成的 makefile 并享受。
需要记住的一件事是,这些工具不是一对一的映射。最明显的区别是 CMake 扫描不同文件(例如 C 头文件和源文件)之间的依赖关系,而 make 将其留给 makefile 作者。
如果这个问题是关于文件的示例Makefile
输出,CMakeList.txt
那么请检查 cmake-backend 源并生成一个这样Makefile
的 . 如果不是,那么添加到@Roberto 的回复中,我试图通过隐藏细节来简化它。
虽然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
。
在areMakefile
中rules 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 就可以像我之前展示的那样减少。
CMake
和中的内部变量Make
现在有点先进了,CMake
我们可以设置一个编译器标志,如下所示,
set(CMAKE_C_FLAGS "-Wall")
请了解有关文件CMake
中默认变量的更多信息CMakeCache.txt
。上面的CMake
代码将等同于Make
下面的代码,
CFLAGS = -Wall
请注意,CFLAGS
是 中的内部变量Make
,同样,CMAKE_C_FLAGS
是 中的内部变量CMake
。
我们可以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 不依赖于自动配置工具)
通常可以使用函数生成一些config.h
文件,就像工具一样。编写自定义函数可以做更多的技巧。最后我们可以选择如下配置,auto-config
configure_file
cmake --build . --config "Release"
可以使用该option
功能添加一些可配置的选项。
如果我们需要用一些调试标志来编译它,我们可以调用make
类似的,
make CXXFLAGS=NDEBUG
我认为内部变量,Makefile-rules
并且CMake-functions
是比较的良好开端,祝您好运。