128

我想知道是否有任何用于Makefiles ( make) 和CMakeLists.txt( cmake) 的示例代码都做同样的事情(唯一的区别是一个写在里面make,另一个写在里面cmake)。

我尝试寻找'cmake vs make',但我从未找到任何代码比较。即使只是一个简单的案例,理解这些差异也会很有帮助。

4

3 回答 3

128

以下 Makefile 构建了一个以prog源 命名的可执行文件prog1.c, prog2.c, prog3.c and main.cprog链接到libmystatlib.a 并且libmydynlib.so它们都是从源代码构建的。此外,使用in 中prog的库及其在. Makefile 默认构建一个发布目标,但也提供一个调试目标:libstuff.astuff/libstuff/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获得。

于 2013-10-09T08:06:30.630 回答
7

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

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

于 2012-06-11T17:53:11.430 回答
4

如果这个问题是关于文件的示例Makefile输出,CMakeList.txt那么请检查 cmake-backend 源并生成一个这样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 函数)Vs Make 规则

在areMakefilerules 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 中添加包含和库路径

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

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

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

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

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

请注意,上面的这些行可以从 auto-gen 工具或 pkg-config 生成。(虽然 Makefile 不依赖于自动配置工具)

CMake 配置/tweek

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

cmake --build . --config "Release"

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

Makefile 配置/调整

如果我们需要用一些调试标志来编译它,我们可以调用make类似的,

make CXXFLAGS=NDEBUG

我认为内部变量,Makefile-rules并且CMake-functions是比较的良好开端,祝您好运。

于 2018-03-15T00:08:08.517 回答