CMake Tutorial 巡礼(11)_添加导出参数

CMake Tutorial 巡礼(11)_ 添加导出参数

这是本系列的第十二篇。
上一篇我们学习了如何添加生成器表达式。这一篇我们来学习如何添加导出参数。

在这里插入图片描述

本章导读

第十一步 添加导出参数

During Installing and Testing of the tutorial we added the ability for CMake to install the library and headers of the project. During Packaging an Installer we added the ability to package up this information so it could be distributed to other people.

在Tutorial的Installing and Testing 一章我们为CMake添加了项目安装库及头文件的功能。在 Packaging an Installer 一章中,我们添加了将这些信息打包起来,这样可以被其他人所知的功能。

The next step is to add the necessary information so that other CMake projects can use our project, be it from a build directory, a local install or when packaged.

下一步是添加必要的信息,以便其他CMake项目可以使用我们的项目,无论是从构建目录、本地安装还是打包时。

The first step is to update our install(TARGETS) commands to not only specify a DESTINATION but also an EXPORT. The EXPORT keyword generates a CMake file containing code to import all targets listed in the install command from the installation tree. So let’s go ahead and explicitly EXPORT the MathFunctions library by updating the install command in MathFunctions/CMakeLists.txt to look like:

第一步是更新我们的install(TARGETS)命令,不仅指定 DESTINATION ,还指定EXPORTEXPORT 关键字生成一个CMake文件,其中包含从安装树导入install命令中列出的所有目标的代码。因此,让我们继续,通过更新MathFunctions/CmakeList中的install命令,显式地导出。MathFunctions/CMakeLists.txt看起来像

MathFunctions/CMakeLists.txt

set(installable_libs MathFunctions tutorial_compiler_flags)
if(TARGET SqrtLibrary)
  list(APPEND installable_libs SqrtLibrary)
endif()
install(TARGETS ${installable_libs}
        EXPORT MathFunctionsTargets
        DESTINATION lib)
install(FILES MathFunctions.h DESTINATION include)

Now that we have MathFunctions being exported, we also need to explicitly install the generated MathFunctionsTargets.cmake file. This is done by adding the following to the bottom of the top-level CMakeLists.txt:

现在我们让MathFunctions导出了,我们同时也需要显示地安装生成的MathFunctionsTargets.cmake文件。这是通过在顶层CMakeLists.txt的底部添加以下内容来实现的。
CMakeLists.txt

install(EXPORT MathFunctionsTargets
  FILE MathFunctionsTargets.cmake
  DESTINATION lib/cmake/MathFunctions
)

At this point you should try and run CMake. If everything is setup properly you will see that CMake will generate an error that looks like:

此处你应该尝试在CMake上运行。如果所有的设置都正确,你将会看到CMake报出了一个像这样的错误:

Target “MathFunctions” INTERFACE_INCLUDE_DIRECTORIES property contains path:
“/Users/robert/Documents/CMakeClass/Tutorial/Step11/MathFunctions” which is prefixed in the source directory.

What CMake is trying to say is that during generating the export information it will export a path that is intrinsically tied to the current machine and will not be valid on other machines. The solution to this is to update the MathFunctions target_include_directories() to understand that it needs different INTERFACE locations when being used from within the build directory and from an install / package. This means converting the target_include_directories() call for MathFunctions to look like:

CMake想要告诉你的是在生成导出信息时,它将导出一个路径,但这个路径相关的一系列地址和当前的设备绑定,在其他设备上将会不合法。解决办法是更新MathFunctions中的 target_include_directories(),要明白它在编译路径下或在安装包内使用时需要不同的接口位置。即需要将Mathfunctions中的 target_include_directories()调用改成如下这样:

MathFunctions/CMakeLists.txt

target_include_directories(MathFunctions
                           INTERFACE
                            $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
                            $<INSTALL_INTERFACE:include>
                           )

Once this has been updated, we can re-run CMake and verify that it doesn’t warn anymore.

只要将这条修复掉,我们在重新执行CMake时就可以保证不再有警告了。

小白按: 此处容易错的地方在于,MathFunctions/CMakeLists.txt中有两条target_include_directories命令,教程要求我们修改的是第一条命令。修改完成后MathFunctions/CMakeLists.txt文件如下所示:

# add the library that runs
add_library(MathFunctions MathFunctions.cxx)

# state that anybody linking to us needs to include the current source dir
# to find MathFunctions.h, while we don't.
target_include_directories(MathFunctions
                           INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
                           )

# should we use our own math functions
option(USE_MYMATH "Use tutorial provided math implementation" ON)
if(USE_MYMATH)

  target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")

  # first we add the executable that generates the table
  add_executable(MakeTable MakeTable.cxx)
  target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags)

  # add the command to generate the source code
  add_custom_command(
    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
    COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
    DEPENDS MakeTable
    )

  # library that just does sqrt
  add_library(SqrtLibrary STATIC
              mysqrt.cxx
              ${CMAKE_CURRENT_BINARY_DIR}/Table.h
              )

  # state that we depend on our binary dir to find Table.h
  target_include_directories(SqrtLibrary PRIVATE
                             ${CMAKE_CURRENT_BINARY_DIR}
                             )

 target_include_directories(MathFunctions
                           INTERFACE
                            $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
                            $<INSTALL_INTERFACE:include>
                           )

  # state that SqrtLibrary need PIC when the default is shared libraries
  set_target_properties(SqrtLibrary PROPERTIES
                        POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
                        )

  target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
  target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()

target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)

# define the symbol stating we are using the declspec(dllexport) when
#building on windows
target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")

# install rules
set(installable_libs MathFunctions tutorial_compiler_flags)
if(TARGET SqrtLibrary)
  list(APPEND installable_libs SqrtLibrary)
endif()
install(TARGETS ${installable_libs}
        EXPORT MathFunctionsTargets
        DESTINATION lib)
install(FILES MathFunctions.h DESTINATION include)

顶层的CMakeLists.txt文件如下所示:

cmake_minimum_required(VERSION 3.15)

# set the project name and version
project(Tutorial VERSION 1.0)

add_library(tutorial_compiler_flags INTERFACE)
target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)

# add compiler warning flags just when building this project via
# the BUILD_INTERFACE genex
set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
target_compile_options(tutorial_compiler_flags INTERFACE
  "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>"
  "$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
)

# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")

option(BUILD_SHARED_LIBS "Build using shared libraries" ON)

# configure a header file to pass the version number only
configure_file(TutorialConfig.h.in TutorialConfig.h)

# add the MathFunctions library
add_subdirectory(MathFunctions)

# add the executable
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial PUBLIC MathFunctions)

# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )

# add the install targets
install(TARGETS Tutorial DESTINATION bin)
install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
  DESTINATION include
  )

# enable testing
enable_testing()

# does the application run
add_test(NAME Runs COMMAND Tutorial 25)

# does the usage message work?
add_test(NAME Usage COMMAND Tutorial)
set_tests_properties(Usage
  PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
  )

# define a function to simplify adding tests
function(do_test target arg result)
  add_test(NAME Comp${arg} COMMAND ${target} ${arg})
  set_tests_properties(Comp${arg}
    PROPERTIES PASS_REGULAR_EXPRESSION ${result}
    )
endfunction()

# do a bunch of result based tests
do_test(Tutorial 4 "4 is 2")
do_test(Tutorial 9 "9 is 3")
do_test(Tutorial 5 "5 is 2.236")
do_test(Tutorial 7 "7 is 2.645")
do_test(Tutorial 25 "25 is 5")
do_test(Tutorial -25 "-25 is (-nan|nan|0)")
do_test(Tutorial 0.0001 "0.0001 is 0.01")

include(InstallRequiredSystemLibraries)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
set(CPACK_SOURCE_GENERATOR "TGZ")
include(CPack)

install(EXPORT MathFunctionsTargets
  FILE MathFunctionsTargets.cmake
  DESTINATION lib/cmake/MathFunctions
)

At this point, we have CMake properly packaging the target information that is required but we will still need to generate a MathFunctionsConfig.cmake so that the CMake find_package() command can find our project. So let’s go ahead and add a new file to the top-level of the project called Config.cmake.in with the following contents:

到此为止,我们已经让CMake很好地打包了所需的目标信息,但是我们仍然需要生成一个MathFunctionConfig.cmake文件,这样CMake的 find_package() 命令才能找得到项目。所以让我们继续,在项目的最顶层路径添加一个新的文件Config.cmake.in,其内容如下:

Config.cmake.in

@PACKAGE_INIT@

include ( "${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )

Then, to properly configure and install that file, add the following to the bottom of the top-level CMakeLists.txt:

然后,为了定义和安装该文件,添加以下内容到顶层CMakeLists.txt的最底部:

CMakeLists.txt

install(EXPORT MathFunctionsTargets
  FILE MathFunctionsTargets.cmake
  DESTINATION lib/cmake/MathFunctions
)

include(CMakePackageConfigHelpers)

Next, we execute the configure_package_config_file(). This command will configure a provided file but with a few specific differences from the standard configure_file() way. To properly utilize this function, the input file should have a single line with the text @PACKAGE_INIT@ in addition to the content that is desired. That variable will be replaced with a block of code which turns set values into relative paths. These values which are new can be referenced by the same name but prepended with a PACKAGE_ prefix.

接着,我们执行configure_package_config_file().这条命令将会指定一个已提供的文件,与标准的 configure_file()方式有一些特别的不同。 为了很好地利用该函数,输入文件应该以@PACKAGE_INIT@为内容单列一行,再添加想要添加的内容。该变量将被一段代码所替换,以将它的值转换为相对路径。这些新变量可以和参考变量名称一致,但要在前面加上一个PACKAGE_ 前缀。

CMakeLists.txt

install(EXPORT MathFunctionsTargets
  FILE MathFunctionsTargets.cmake
  DESTINATION lib/cmake/MathFunctions
)

include(CMakePackageConfigHelpers)
# generate the config file that is includes the exports
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
  INSTALL_DESTINATION "lib/cmake/example"
  NO_SET_AND_CHECK_MACRO
  NO_CHECK_REQUIRED_COMPONENTS_MACRO
  )

The write_basic_package_version_file() is next. This command writes a file which is used by the “find_package” document the version and compatibility of the desired package. Here, we use the Tutorial_VERSION_* variables and say that it is compatible with AnyNewerVersion, which denotes that this version or any higher one are compatible with the requested version.

write_basic_package_version_file()是下一个。这条命令保存了一个文件,用于"find_package"文档,说明所需包的版本和兼容性。这里,我们用Tutorial_VERSION_*变量,并且声明它与任何“更新的版本”都兼容,这表明此版本或任何更高的版本都与请求的版本兼容。

CMakeLists.txt

write_basic_package_version_file(
  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
  VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}"
  COMPATIBILITY AnyNewerVersion
)

Finally, set both generated files to be installed:

最终,设置两个生成的文件安装:

CMakeLists.txt

install(FILES
  ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
  ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake
  DESTINATION lib/cmake/MathFunctions
  )

At this point, we have generated a relocatable CMake Configuration for our project that can be used after the project has been installed or packaged. If we want our project to also be used from a build directory we only have to add the following to the bottom of the top level CMakeLists.txt:

此处,我们在项目安装或打包之后,已经为项目生成了一个重定向CMake配置。如果我们希望项目可以被一个编译路径使用,我们只需要在顶层的CMakeLists.txt文件最末,添加以下内容:

CMakeLists.txt

export(EXPORT MathFunctionsTargets
  FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake"
)

With this export call we now generate a Targets.cmake, allowing the configured MathFunctionsConfig.cmake in the build directory to be used by other projects, without needing it to be installed.

随着导出调用,我们现在生成一个Targets.cmake,允许在任何其他项目的编译路径下使用配置好的MathFunctionsConfig.cmake,而不需要安装它。

小白按: 顶层的CMakeLists.txt为:

cmake_minimum_required(VERSION 3.15)

# set the project name and version
project(Tutorial VERSION 1.0)

add_library(tutorial_compiler_flags INTERFACE)
target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)

# add compiler warning flags just when building this project via
# the BUILD_INTERFACE genex
set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
target_compile_options(tutorial_compiler_flags INTERFACE
  "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>"
  "$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
)

# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")

option(BUILD_SHARED_LIBS "Build using shared libraries" ON)

# configure a header file to pass the version number only
configure_file(TutorialConfig.h.in TutorialConfig.h)

# add the MathFunctions library
add_subdirectory(MathFunctions)

# add the executable
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial PUBLIC MathFunctions)

# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )

# add the install targets
install(TARGETS Tutorial DESTINATION bin)
install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
  DESTINATION include
  )

# enable testing
enable_testing()

# does the application run
add_test(NAME Runs COMMAND Tutorial 25)

# does the usage message work?
add_test(NAME Usage COMMAND Tutorial)
set_tests_properties(Usage
  PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
  )

# define a function to simplify adding tests
function(do_test target arg result)
  add_test(NAME Comp${arg} COMMAND ${target} ${arg})
  set_tests_properties(Comp${arg}
    PROPERTIES PASS_REGULAR_EXPRESSION ${result}
    )
endfunction()

# do a bunch of result based tests
do_test(Tutorial 4 "4 is 2")
do_test(Tutorial 9 "9 is 3")
do_test(Tutorial 5 "5 is 2.236")
do_test(Tutorial 7 "7 is 2.645")
do_test(Tutorial 25 "25 is 5")
do_test(Tutorial -25 "-25 is (-nan|nan|0)")
do_test(Tutorial 0.0001 "0.0001 is 0.01")

include(InstallRequiredSystemLibraries)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
set(CPACK_SOURCE_GENERATOR "TGZ")
include(CPack)

install(EXPORT MathFunctionsTargets
  FILE MathFunctionsTargets.cmake
  DESTINATION lib/cmake/MathFunctions
)

include(CMakePackageConfigHelpers)
# generate the config file that is includes the exports
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
  INSTALL_DESTINATION "lib/cmake/example"
  NO_SET_AND_CHECK_MACRO
  NO_CHECK_REQUIRED_COMPONENTS_MACRO
  )

write_basic_package_version_file(
  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
  VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}"
  COMPATIBILITY AnyNewerVersion
)

install(FILES
  ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
  ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake
  DESTINATION lib/cmake/MathFunctions
  )

export(EXPORT MathFunctionsTargets
  FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake"
)

下一章我们将迎来最终章:打包Debug及Release版本。

【水平所限,错漏难免,创作不易,轻喷勿骂】

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,确保你的项目已经正确地链接了 Emscripten SDK。接下来,在 CMakeLists.txt 中添加以下内容: ```cmake cmake_minimum_required(VERSION 3.0) project(your_project) # 设置编译选项 set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # 添加 Emscripten 编译器 SET(CMAKE_C_COMPILER "emcc") SET(CMAKE_CXX_COMPILER "em++") # 添加 Emscripten 编译选项 SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s WASM=1 -s USE_SDL=2 -s USE_WEBGL2=1 -s FULL_ES3=1 -s USE_GLFW=3") # 添加源代码 add_executable(your_project main.cpp) # 导出 C 函数为 JavaScript 模块 set_target_properties(your_project PROPERTIES LINK_FLAGS "-s EXPORTED_FUNCTIONS='[\"_your_c_function\"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'") # 指定输出文件名 set_target_properties(your_project PROPERTIES OUTPUT_NAME "your_project") # 指定输出文件类型为 JavaScript 模块 set_target_properties(your_project PROPERTIES SUFFIX ".js") # 拷贝输出文件到指定目录 add_custom_command(TARGET your_project POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:your_project> ${CMAKE_CURRENT_SOURCE_DIR}/output/) ``` 以上代码做了以下几件事: 1. 设置编译选项,包括编译标准、编译器等等。 2. 添加 Emscripten 编译器和编译选项。 3. 添加源代码。 4. 导出 C 函数为 JavaScript 模块,这里的 `_your_c_function` 是你需要导出的函数名。 5. 指定输出文件名为 `your_project.js`。 6. 拷贝输出文件到指定目录。 最后,你可以通过以下命令来生成 WebAssembly 项目: ```bash mkdir build && cd build cmake .. make ``` 如果一切顺利,你将得到 `your_project.js` 和 `your_project.wasm` 两个文件,其中前者是 JavaScript 模块,后者是 WebAssembly 模块。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值