build - CMake自定义构建问题

标签 build cmake emscripten

我正在尝试使用CMake构建自定义项目,这涉及使用emscripten为我的C++库提供javascript绑定(bind)。

这就是我想要实现的CMakeLists.txt文件

  • 为我的文件指定源位置(DONE)
  • 设置要使用的相关编译器以及编译器标志等(DONE)
  • 使用自定义生成生成新的cpp文件(以下详细步骤)
  • 使用自定义工具(python脚本)生成interface/glue.cpp
  • 创建一个新的EMPTY文件interface/glue_wrapper.cpp
  • 对于f中的每个头文件${my_header_files},将#include "f"附加到文件interface/glue_wrapper.cpp
  • interface/glue_wrapper.cpp中的最终条目应为#include "glue.cpp"
  • 使用以下逻辑使用自定义版本生成我的javascript文件:
  • 创建一个变量$ {ALL_SOURCES},其中包含上面
  • 中第1步中列出的所有源和第3步中的interface/glue_wrapper.cpp
  • 使用以下命令编译:${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${ALL_SOURCES} interface/glue_wrapper.cpp --post-js glue.js -o output.js

  • 我在第3步和第4步上花了最后7个小时-均未成功。

    这就是我到目前为止(与上面的步骤3和4有关)
    # Build Interface
    ADD_CUSTOM_COMMAND(
                    OUTPUT interface/glue.cpp
                    COMMAND cd interface
                    COMMAND python ${PLATFORM_PREFIX}/tools/webidl_binder.py ${myclasses_INTERFACE} glue
                    # Need to loop through list and generate include statements ...
                    #COMMAND echo "#include <glue.cpp>" > glue_wrapper.cpp
                     )
    
    # Build JS library
    ADD_CUSTOM_COMMAND(
                    OUTPUT ${PROJECT_JS_DIR}/${PROJECT}.js
                    COMMAND ${CMAKE_CXX_COMPILER} # Nothing seems to work anyway .... giving up finally :(
                    )
    

    我正在使用cmake 3.2.1,并在Ubuntu 14.0.4上构建。我正在尝试创建Unix MakeFiles。

    我的问题是这样的:

    为了实现第3步和第4步中指定的功能,如何修改上面的代码片段?

    最佳答案

    看来glue_wrapper.cpp的内容根本不依赖于构建时值,它们纯粹基于CMake时可用的信息(my_header_files变量的内容)。因此,您可以使用简单的file()命令在CMake时创建文件:

    file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/interface/glue_wrapper.cpp)  # erase file if it exists
    foreach(header IN LISTS my_header_files ITEMS glue.cpp)
      file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/interface/glue_wrapper.cpp "#include \"${header}\"\n")
    endforeach()
    

    用于创建.js库的自定义命令应正常运行:
    add_custom_command(
      OUTPUT ${PROJECT_JS_DIR}/${PROJECT}.js
      COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${ALL_SOURCES} interface/glue_wrapper.cpp --post-js glue.js -o output.js
      DEPENDS ${ALL_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/interface/glue_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/interface/glue.cpp
      COMMENT "Building ${PROJECT}.js"
      VERBATIM
    )
    

    与任何CMake自定义命令一样,只有在某些方面取决于其输出时,它才会包含在构建中(我怀疑这就是您的方法失败的原因)。因此,您应该添加一个自定义目标来驱动命令:
    add_custom_target(
      JsLibrary ALL
      DEPENDS ${PROJECT_JS_DIR}/${PROJECT}.js
      COMMENT "Building JsLibrary"
    )
    

    那应该是所有必要的。

    作为附带说明,请注意add_custom_command具有WORKING_DIRECTORY参数,您应该使用该参数代替COMMAND cd

    自定义命令和自定义目标之间的CMake关系可能需要一些时间才能完全理解,因此我将尝试解释上面代码中的情况。

    自定义命令

    命令add_custom_command(OUTPUT x ...)创建一个生成规则,该规则生成一个输出。基本上,这告诉CMake:

    如果有人需要x文件,请按以下步骤创建它。

    该命令本身不会向生成的构建系统添加任何内容。它仅向CMake提供有关如何创建文件的信息。

    调用的各个组成部分是:
    add_custom_command(
      OUTPUT ${PROJECT_JS_DIR}/${PROJECT}.js
    

    此自定义命令生成的文件。它说:“custom命令生成这些文件。”
      COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${ALL_SOURCES} interface/glue_wrapper.cpp --post-js glue.js -o output.js
    
    COMMAND参数介绍要执行的命令的命令行。它说:“这是产生OUTPUT中列出的文件所必须要做的。”
      DEPENDS ${ALL_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/interface/glue_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/interface/glue.cpp
    
    DEPENDS部分介绍命令的依赖关系(先决条件)。紧随其后的每个项目都是一个文件,该文件是命令的依赖项。它说:“如果缺少这些文件中的任何一个,或者如果这些文件中的任何一个比输出文件中的任何新,则必须重新运行此命令。”

    特别注意对${CMAKE_CURRENT_BINARY_DIR}/interface/glue.cpp的依赖,我将在稍后再讨论。
      COMMENT "Building ${PROJECT}.js"
    

    这纯粹是文档,将在执行自定义命令(=内置)时打印。
      VERBATIM
    )
    

    这告诉CMake适当地转义将执行命令的shell的COMMAND节中的任何特殊字符。基本上,除非您确实有理由不这么做,否则始终将其放入自定义命令中。

    自定义目标

    如前所述,CMake仅在某些请求其输出的情况下才将自定义命令添加到构建系统。普通目标(例如库或可执行文件)可以通过在源文件中列出输出文件来实现此目的。这在自定义命令例如从IDL定义生成C++源文件的情况下是典型的。

    自定义命令还可以在其DEPENDS节中列出另一个自定义命令的输出,从而创建所需的依赖关系。但是,只有在某处请求“master”命令的输出时,这两者才会再次包括在内。

    如果生成的文件实际上是最终产品,而不仅仅是正常目标的源文件,则必须在某处指定对其的显式依赖关系以确保生成了该文件。这就是自定义目标的来源。它是一个目标(就像可执行文件或库一样),因此它将始终存在于构建系统中。当使用基于makefile的生成器时,自定义目标只是一个额外的规则。让我们分析一下我在上面的答案中输入的内容:
    add_custom_target(
      JsLibrary
    
    JsLibrary只是目标的符号名称。可以是您想要的任何东西。您将在命令行上键入该名称以构建.js文件:> make JsLibrary
    ALL
    

    默认情况下,自定义目标不属于all调用的make all目标的一部分;您必须对它们进行make明确编码。添加ALL参数将成为make all的自定义目标部分,我假设您会在此处使用。
    DEPENDS ${PROJECT_JS_DIR}/${PROJECT}.js
    

    这是关键所在,也是我们首先创建自定义目标的原因。这告诉CMake定制目标取决于生成的文件。现在CMake看到了构建系统一部分所需的文件(即通过自定义命令JsLibrary),并查看它是否知道如何创建这样的文件。它找到定制命令,并确保将适当的规则添加到生成的构建系统中。
      COMMENT "Building JsLibrary"
    )
    

    再次,这是纯粹的文档-每次创建目标时都会打印(即使其所有依赖关系都是最新的,因此也不会进行进一步处理)。

    总结
    JsLibrary将包含在构建系统中,因为它是一个自定义目标,并且始终包含自定义目标。这将是make all的一部分,因为我们在创建时指定了ALL
    JsLibrary取决于${PROJECT_JS_DIR}/${PROJECT}.js,因此由custom命令创建的规则将包含在构建系统中,并在每次构建JsLibrary时进行检查。如果过时,它将被执行。
    ${PROJECT_JS_DIR}/${PROJECT}.js依次取决于${CMAKE_CURRENT_BINARY_DIR}/interface/glue.cpp,因为这是在创建DEPENDS的自定义命令的.js部分中指定的。因此,在创建glue.cpp的自定义命令中描述的规则也将包含在构建系统中,并且一切正常。

    关于build - CMake自定义构建问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30112274/

    相关文章:

    objective-c - iOS - 构建失败,CocoaPods 找不到头文件

    memory - 从编译为 Emscripten 的 Rust 获取 Javascript 中的数组

    javascript - 如何将 LLVM IR br 转换回 while 循环

    boost - cmake 找不到 boost 线程

    c# - Visual Studio 2008 是否能够对 C# 进行条件编译?

    react-native - 世博会无法建立,请求失败,状态码为400

    xcode - 构建静态库

    c++ - 使用 CMake 和 Boost 单元测试进行编译

    cmake - add_subdirectory() 不安装任何东西

    linux - makefile 中的 shell 命令