Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用GLOB指定源文件更好,还是在CMake中单独指定每个文件更好?_Cmake - Fatal编程技术网

使用GLOB指定源文件更好,还是在CMake中单独指定每个文件更好?

使用GLOB指定源文件更好,还是在CMake中单独指定每个文件更好?,cmake,Cmake,CMake提供了几种为目标指定源文件的方法。 一种是使用globbing(),例如: FILE(GLOB MY_SRCS dir/*) 另一种方法是单独指定每个文件 哪种方式比较好?Globbing似乎很简单,但我听说它有一些缺点。完全披露:我最初更喜欢Globbing方法,因为它简单,但多年来我逐渐认识到,显式列出文件对于大型、多开发人员项目来说不太容易出错 原始答复: 全球化的优势在于: 添加新文件时很容易 仅在一个位置列出:在 磁盘。不全球化会造成 重复 您的CMakeLists.t

CMake提供了几种为目标指定源文件的方法。 一种是使用globbing(),例如:

FILE(GLOB MY_SRCS dir/*)
另一种方法是单独指定每个文件


哪种方式比较好?Globbing似乎很简单,但我听说它有一些缺点。

完全披露:我最初更喜欢Globbing方法,因为它简单,但多年来我逐渐认识到,显式列出文件对于大型、多开发人员项目来说不太容易出错

原始答复:


全球化的优势在于:

  • 添加新文件时很容易 仅在一个位置列出:在 磁盘。不全球化会造成 重复

  • 您的CMakeLists.txt文件将 更短的这是一个很大的优势,如果你 我有很多文件。不全球化 导致您丢失CMake逻辑 在巨大的文件列表中

使用硬编码文件列表的优点是:

  • CMake将正确跟踪磁盘上新文件的依赖项-如果我们使用 glob则当您运行CMake时,第一轮未全局化的文件将无法获取 拾起

  • 确保只添加所需的文件。地球人可能会捡起流浪汉 您不需要的文件

为了解决第一个问题,您可以使用touch命令或在不做任何更改的情况下写入文件,简单地“触摸”执行glob的CMakeLists.txt。这将迫使CMake重新运行并拾取新文件

要解决第二个问题,您可以仔细地将代码组织到目录中,这可能是您无论如何都要做的。在最坏的情况下,您可以使用
list(REMOVE_ITEM)
命令清理全局文件列表:

file(GLOB to_remove file_to_remove.cpp)
list(REMOVE_ITEM list ${to_remove})

如果您正在使用类似于在同一构建目录中尝试代码的旧版本的东西,那么这可能会对您造成影响。在这种情况下,您可能需要清理和编译更多的文件,以确保在列表中获得正确的文件。这是一个非常棘手的问题,而且您已经开始注意了,所以这不是一个真正的问题。

在CMake中指定源文件的最佳方法是通过明确列出它们

CMake的创建者自己建议不要使用globbing

见:

(我们不建议使用GLOB从源代码树中收集源文件列表。如果在添加或删除源时没有更改CMakeLists.txt文件,则生成的生成系统无法知道何时要求CMake重新生成。)

当然,你可能想知道缺点是什么——继续读下去


全球化失败时:
全局绑定的最大缺点是创建/删除文件不会自动更新生成系统

如果您是添加文件的人,这似乎是一个可以接受的折衷方案,但是这会给构建代码的其他人带来问题,他们会从版本控制更新项目,运行build,然后与您联系,抱怨
“构建已损坏”。

更糟糕的是,故障通常会导致一些链接错误,而这些错误不会对问题的原因给出任何提示,排除故障会浪费时间

在我参与的一个项目中,我们开始使用globbing,但当添加新文件时,我们收到了很多抱怨,因此有足够的理由明确列出文件而不是globbing

这也破坏了常见的git工作流程
git对分
和功能分支之间的切换)

所以我不能推荐这个,它造成的问题远远超过了便利性,当有人因为这个原因无法构建您的软件时,他们可能会浪费很多时间来跟踪问题,或者干脆放弃

另一个注意事项是,仅仅记住触摸
CMakeLists.txt
并不总是足够的,对于使用globbing的自动构建,我必须在每个构建之前运行
cmake
,因为自上次构建以来可能已经添加/删除了文件*

该规则的例外情况: 在某些情况下,全球化更可取:

  • 用于为不使用CMake的现有项目设置
    CMakeLists.txt
    文件。
    这是一种快速获取所有引用源代码的方法(一旦构建系统运行-用显式文件列表替换globbing)
  • 当CMake未用作主要的生成系统时,例如,如果您正在使用一个不使用CMake的项目,并且您希望为其维护自己的生成系统
  • 对于文件列表经常更改以致无法维护的任何情况。在这种情况下,它可能是有用的,但是您必须接受每次运行
    cmake
    生成构建文件,以获得可靠/正确的构建(这与cmake的意图背道而驰,即从构建中分离配置的能力)

*是的,我本可以编写一个代码来比较更新前后磁盘上的文件树,但这不是一个很好的解决方法,最好留给构建系统来处理。

您可以安全地全局(可能也应该这样做),而代价是增加一个文件来保存依赖项

在某处添加如下函数:

# Compare the new contents with the existing file, if it exists and is the 
# same we don't want to trigger a make by changing its timestamp.
function(update_file path content)
    set(old_content "")
    if(EXISTS "${path}")
        file(READ "${path}" old_content)
    endif()
    if(NOT old_content STREQUAL content)
        file(WRITE "${path}" "${content}")
    endif()
endfunction(update_file)

# Creates a file called CMakeDeps.cmake next to your CMakeLists.txt with
# the list of dependencies in it - this file should be treated as part of 
# CMakeLists.txt (source controlled, etc.).
function(update_deps_file deps)
    set(deps_file "CMakeDeps.cmake")
    # Normalize the list so it's the same on every machine
    list(REMOVE_DUPLICATES deps)
    foreach(dep IN LISTS deps)
        file(RELATIVE_PATH rel_dep ${CMAKE_CURRENT_SOURCE_DIR} ${dep})
        list(APPEND rel_deps ${rel_dep})
    endforeach(dep)
    list(SORT rel_deps)
    # Update the deps file
    set(content "# generated by make process\nset(sources ${rel_deps})\n")
    update_file(${deps_file} "${content}")
    # Include the file so it's tracked as a generation dependency we don't
    # need the content.
    include(${deps_file})
endfunction(update_deps_file)
然后去环球旅行:

file(GLOB_RECURSE sources LIST_DIRECTORIES false *.h *.cpp)
update_deps_file("${sources}")
add_executable(test ${sources})
像以前一样,您仍然在处理显式依赖项(并触发所有自动构建!),只是它位于两个文件中而不是一个文件中


过程中唯一的更改是在创建新文件之后。如果您不使用glob,则工作流将从Visual Studio内部修改CMakeLists.txt并重新生成,如果使用glob,则显式运行cmake,或者只需触摸CMakeLists.txt。

分别指定每个文件

我使用传统的CMakeLists.txt和python脚本来更新它。我在添加文件后手动运行python脚本

请看我的回答:

在CMake 3.12中,获得的命令取决于
CONFIGURE\u# Whenever this glob's value changes, cmake will rerun and update the build with the
# new/removed files.
file(GLOB_RECURSE sources CONFIGURE_DEPENDS "*.cpp")

add_executable(my_target ${sources})