制造与制造样品代码?

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

我尝试查找“ cmake vs make”,但是没有找到任何代码比较。即使只是为了一个简单的案例,理解它们之间的区别也是非常有帮助的。

56946 次浏览

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

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

下面的 Makefile 从源代码生成一个名为 prog的可执行文件 proglibmystatlib.a相连 和 libmydynlib.so都是从源代码构建的。此外,prog使用 stuff/lib中的库 libstuff.astuff/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) 当然,CMake 在第三方时真正开始发光发亮 库(如 OpenGL)是以可移植的方式包含的。

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

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

如果这个问题是关于 CMakeList.txt文件的样例 Makefile输出,那么请检查 cmake-backend 源代码并生成这样的 Makefile。如果这不是然后添加到@罗伯托的回复,我试图通过隐藏的细节使它简单。

启动程序

虽然 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 制定规则

Makefile中使用的是 rules and recipes而不是 functions。除了类似 function的功能,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-document 中找到。一些隐式变量在这里也是相关的。

注意,Makefile提供了显示构建可以完成的 how的详细信息 recipe。可以编写 executable.mk来保持在一个文件中定义的详细信息。这样,makefile 就可以像我前面展示的那样减少。

CMakeMake中的内部变量

现在稍微进一步,在 CMake中我们可以像下面这样设置一个编译器标志,

set(CMAKE_C_FLAGS "-Wall")

请在 CMakeCache.txt文件中找到更多关于 CMake默认变量的信息。 上面的 CMake代码相当于下面的 Make代码,

CFLAGS = -Wall

请注意,CFLAGSMake中的一个内部变量,同样地,CMAKE_C_FLAGSCMake中的一个内部变量。

在 CMake 中添加包含和库路径

我们可以使用函数在 cmake中完成。

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

在 Make 中添加 include 和库路径

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

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

注意,上面的代码行可以从 auto-gen 工具或 pkg-config 生成(尽管 Makefile 不依赖于 auto-config 工具)

CMake configure/tweek

通常可以使用 configure_file函数生成一些类似于 auto-config工具的 config.h文件。编写自定义函数可能需要更多技巧。最后我们可以像下面这样选择一个配置,

cmake --build . --config "Release"

可以使用 option函数添加一些可配置选项。

Makefile configure/tweak

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

make CXXFLAGS=NDEBUG

我认为内部变量 Makefile-rulesCMake-functions是比较的良好开端,祝你好运,继续挖掘。