使用CMake调用Makefile 项目

简介: 使用CMake调用Makefile 项目

基本示例

如果项目是使用传统的Makefile构建的,并且您希望使用CMake调用这些Makefile,您可以使用CMake的add_custom_targetadd_custom_command命令来实现。

首先,创建一个CMakeLists.txt文件。然后,在其中使用add_custom_targetadd_custom_command来调用您的原始Makefile。

现在用一共示例来说明,假如有以下的项目结构

project/
├── build/
├── CMakeLists.txt
├── Makefile
└── src/
    ├── Makefile
    └── main.cc

这是一个简单的项目,其中src目录包含一个main.cc文件。接下来,我们需要编写两个Makefile。

  1. 在项目的根目录下创建一个Makefile:
    在项目的根目录下的Makefile中,您可以使用$(MAKE)命令来调用src目录下的Makefile。:
# project/Makefile
.PHONY: all
all: call_src_makefile
@echo %date% %time% - Running target 'all'
call_src_makefile:
$(MAKE) -C src
clean:
  $(MAKE) -C src clean
  1. 这个Makefile现在定义了两个目标:allcleanall目标依赖于build_src_makefile目标,当您在顶层目录中运行makemake all时,它会调用src目录下的Makefile来构建项目。同样,clean目标会调用src目录下的Makefile中的clean目标来清理构建产物。
  2. src目录下创建另一个Makefile:
# project/src/Makefile
CC = g++
CFLAGS = -Wall -std=c++11
TARGET = main
SOURCES = main.cc
all: $(TARGET)
$(TARGET): $(SOURCES)
  $(CC) $(CFLAGS) $(SOURCES) -o $(TARGET)
clean:
  rm -f $(TARGET)
  1. 此Makefile负责编译main.cc并生成一个名为main的可执行文件。
  2. 创建一个简单的main.cc文件:
// project/src/main.cc
#include <iostream>
int main() {
    std::cout << "Hello, world!" << std::endl;
    return 0;
}
  1. 确保项目根目录下的CMakeLists.txt文件包含以下内容:
cmake_minimum_required(VERSION 3.10)
project(MyProject)
add_custom_target(build_top_level_makefile
                  COMMAND make -C ${CMAKE_CURRENT_SOURCE_DIR}
                  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
add_custom_target(build_src_makefile
                  COMMAND make -C ${CMAKE_CURRENT_SOURCE_DIR}/src
                  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src)
  1. 切换到build目录,并运行cmake
cd build
cmake ..
  1. 这将在build目录下生成CMake的Makefile。
  2. build目录下运行make
make build_top_level_makefile
  1. 或者直接运行:
make build_src_makefile
  1. 这将使用src目录下的Makefile构建项目。
  2. 运行生成的可执行文件:
../src/main

说明:如何传递给具体的makefile文件

make -f 命令

make 是一个用于自动构建可执行程序和库的工具,它使用名为 Makefile 的文件,其中包含了一些规则和依赖来决定如何构建目标。

-fmake 的一个命令行选项,它允许你指定一个不同于默认的 Makefile 文件。默认情况下,make 命令会在当前目录下寻找一个名为 Makefile 的文件。如果你想使用一个不同的文件,比如 Makefile1,你可以使用 -f 选项指定它,如 make -f Makefile1

当你运行 make -f Makefile1 时,make 会读取 Makefile1 文件,并查找第一个目标(或者默认目标)。默认目标通常是文件的第一个目标,但也可以通过 .DEFAULT 特殊目标来显式设置。make 会尝试构建这个目标,并在需要时,根据 Makefile1 中定义的规则和依赖,构建其他目标。

如果你想构建 Makefile1 中定义的特定目标,你可以在 make -f Makefile1 命令后面添加目标名称,如 make -f Makefile1 targetname。在这种情况下,make 会尝试只构建 targetname,以及任何 targetname 依赖的目标。

总的来说,make -f 命令使你能够使用不同的 Makefile 文件,或者在同一个 Makefile 中构建不同的目标。

make include指令

Makefile 中,include 指令用于包含其他的 Makefile 文件。这个指令允许你将一个大的 Makefile 分割成多个小的,易于管理和重用的文件。

Makefile 文件中出现 include 指令时,make 将会读取并处理指定的文件,就像这些文件的内容直接插入到 include 指令的位置一样。这意味着被包含文件中的所有规则、目标、变量定义等都将被添加到主 Makefile 中。

被包含的 Makefile 文件中的规则和目标是独立的,它们不会因为被包含而改变。如果一个目标在多个被包含的 Makefile 中都有定义,或者在主 Makefile 和一个或多个被包含的 Makefile 中都有定义,那么 make 将会使用最后一个定义的规则。在处理 Makefile 时,make 会依次读取文件,所以最后读取的文件中的定义将覆盖之前的定义。

例如,如果你有以下的 Makefile

include Makefile1
include Makefile2

Makefile1Makefile2 中都定义了一个名为 target 的目标,那么 make target 将会使用 Makefile2 中的定义,因为 Makefile2 是最后被读取的。

然而,通常来说,为了避免混乱和不确定性,最好在 Makefile 文件中避免目标和规则的名字重复。如果你需要在多个 Makefile 中使用相同的目标名,可能需要重新考虑你的构建系统设计。

传递

make -C ${CMAKE_CURRENT_SOURCE_DIR}命令会在${CMAKE_CURRENT_SOURCE_DIR}目录下执行make,并寻找名为Makefile的文件来执行。在一个目录下通常只应有一个Makefile

如果${CMAKE_CURRENT_SOURCE_DIR}目录下有多个Makefile,那么通常需要使用不同的名称来区分它们,例如Makefile1Makefile2。在这种情况下,make -C ${CMAKE_CURRENT_SOURCE_DIR}命令将不知道应该执行哪个Makefile,除非你指定具体的文件名,例如make -f Makefile1 -C ${CMAKE_CURRENT_SOURCE_DIR}

因此,如果${CMAKE_CURRENT_SOURCE_DIR}目录下有多个Makefilemake -C ${CMAKE_CURRENT_SOURCE_DIR}命令默认会找到并执行名为Makefile的文件。如果有多个文件都叫Makefile,那么这个命令可能会出错,或者只执行其中一个Makefile,具体哪个可能取决于文件系统的行为。

Cmake传递lib给Makefile

将CMake引用的库连接到调用的Makefile中需要手动处理一些细节,但这是可行的。以下是一种可能的方法:

  1. 在您的CMakeLists.txt中,找到和引用的库相关的信息,包括库文件的路径和链接选项。例如,如果您使用find_packagetarget_link_libraries来引用库,那么您需要找到这些库的路径和链接选项。
  2. 创建一个新的Makefile变量,用于传递库信息给被调用的Makefile。例如,您可以创建一个名为LIBS的变量,并将CMake找到的库信息赋值给它。
  3. 修改被调用的Makefile,使其能够接收并使用从CMake传递的库信息。在Makefile中,您需要使用$(LIBS)变量来添加库链接选项。

例如,您的CMakeLists.txt文件可能如下所示:

cmake_minimum_required(VERSION 3.10)
project(MyProject)
# Find your libraries using find_package or other methods
find_package(YourLibrary REQUIRED)
# ...
add_custom_target(build_with_libs
                  COMMAND make -C ${CMAKE_CURRENT_SOURCE_DIR} LIBS="${YourLibrary_LIBRARIES}"
                  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})

接下来,修改您的Makefile,以便它能够接收和使用LIBS变量。例如:

# Your original Makefile content
# Add the library information passed from CMake
LDFLAGS += $(LIBS)
# ...

这样,当您通过CMake调用Makefile时,CMake找到的库信息将被传递给Makefile,并用于链接过程。

Cmake传递参数给Makefile,比如make clean

我的目的是希望通过cmake生成的makefile直接传递参数给我的主makefile

修改CMakeLists.txt

以下是一个在CMakeLists.txt中添加自定义目标的示例:

cmake_minimum_required(VERSION 3.10)
project(MyProject)
find_library(MY_LIBRARY my_library)
find_path(MY_INCLUDE_DIR my_header.h)
function(add_custom_make_target TARGET_NAME EXTRA_ARGS)
  add_custom_target(${TARGET_NAME}
                    COMMAND ${CMAKE_MAKE_PROGRAM} -C ${CMAKE_SOURCE_DIR} ${TARGET_NAME} ${EXTRA_ARGS}
                    WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
endfunction()
add_custom_target(default_target ALL
                  COMMAND MY_LIBRARY=${MY_LIBRARY} MY_INCLUDE_DIR=${MY_INCLUDE_DIR} ${CMAKE_MAKE_PROGRAM} -C ${CMAKE_SOURCE_DIR}
                  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
#add_custom_make_target(clean)
add_custom_make_target(clean_all "")
add_custom_make_target(clean_global "")
add_custom_make_target(generate "MY_LIBRARY=${MY_LIBRARY} MY_INCLUDE_DIR=${MY_INCLUDE_DIR}")
add_custom_make_target(make_parallel "")
add_custom_make_target(preprocess "")
add_custom_make_target(check_dups "")
add_custom_make_target(flat_src "")
add_custom_make_target(mak "")

Windows下使用Cmake调用Makefile

在Windows上使用CMake调用Makefile是可行的,但需要考虑一些额外因素。首先,Windows上没有默认的Make工具,因此您需要安装GNU Make或其他Make实现。GNU Make通常可以通过安装MinGW或Cygwin获得。

然后,确保将Make工具添加到系统的PATH环境变量中,以便CMake可以找到并调用它。当您在Windows上使用CMake时,生成的构建系统可能是Visual Studio解决方案或NMake文件。因此,调用Makefile时,您需要确保使用了正确的构建系统。

例如,假设您已经安装了GNU Make并将其添加到了系统PATH中。在CMakeLists.txt中,您可以创建一个自定义目标,以便在Windows上调用Makefile:

cmake_minimum_required(VERSION 3.10)
project(MyProject)
# ...
if(WIN32)
    add_custom_target(build_with_makefile
                      COMMAND make -C ${CMAKE_CURRENT_SOURCE_DIR}
                      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endif()

在Windows上使用CMake生成构建文件时,您可能需要指定一个生成器。例如,您可以使用命令行选项-G指定生成器:

cmake -G "MinGW Makefiles" ..

这将生成适用于MinGW Make的Makefile。然后,您可以使用cmake --build . --target build_with_makefile命令来调用CMakeLists.txt中定义的自定义目标,进而调用您的原始Makefile。

注意,Visual Studio解决方案使用MSBuild作为其构建系统,而不是Make。当您在Windows上使用CMake生成Visual Studio解决方案时,CMake会生成一个.sln文件和多个.vcxproj文件,这些文件与MSBuild一起工作。在这种情况下,直接在CMakeLists.txt中调用原始的Makefile是不合适的。

不过,如果您仍然需要在Visual Studio解决方案中调用Makefile,可以创建一个自定义的构建事件。您可以在Visual Studio项目属性中设置这个事件,以在构建过程的某个特定阶段调用Makefile。具体操作如下:

  1. 在Visual Studio中打开您的项目。
  2. 右键点击项目名称,选择“属性”。
  3. 在“配置属性”下展开“生成事件”。
  4. 在“预生成事件命令行”、“预链接事件命令行”或“后生成事件命令行”中输入执行Makefile所需的命令。例如,您可以输入make -C "$(ProjectDir)",其中$(ProjectDir)是Visual Studio的一个宏,代表项目目录的路径。
  5. 点击“应用”,然后点击“确定”。

现在,在Visual Studio构建解决方案时,将在指定的构建阶段执行Makefile。需要注意的是,这种方法与CMake在很大程度上是分离的,因此您可能需要手动管理库依赖关系和其他构建设置。


目录
相关文章
|
6月前
CMake基础(4)动态库
CMake基础(4)动态库
63 1
|
6月前
|
自然语言处理
CMake基础(3)静态库
CMake基础(3)静态库
77 1
|
5月前
我为什么更推荐你使用cmake编译grpc程序?
我为什么更推荐你使用cmake编译grpc程序?
103 0
|
6月前
|
编译器 C语言 C++
CMake基础(9)使用Clang编译
CMake基础(9)使用Clang编译
456 0
|
6月前
|
iOS开发 MacOS
CMake基础:CMake中的常用变量的命令
CMake基础:CMake中的常用变量的命令
63 0
|
Linux 开发工具 C语言
Linux编译gcc/g++、自动化构建工具make/makefile
Linux中关于gcc/g++的基本操作,以及makefile的基本操作。
Linux编译gcc/g++、自动化构建工具make/makefile
CMake教程5:可执行程序调用lib
CMake教程5:可执行程序调用lib
365 0
|
IDE 开发工具
CMake教程3:最简单的CMake可执行程序
CMake教程3:最简单的CMake可执行程序
195 0
|
关系型数据库 MySQL C语言
cmake编译问题解决
<p><br></p> <p></p> <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> <strong>2 安装cmake软件包</strong><br> yu
30807 0
|
Shell
构建工具:Make和Makefile
构建工具:Make和Makefile