2016-12-28 184 views
5

我有一个C++项目,它使用CMake作为其构建系统。我想以下行为:在默认情况下优化CMake

如果cmake的被调用为cmake ..,然后CMAKE_CXX_FLAGS-O3 -Wall -Wextra

如果cmake的被调用为cmake .. -DCMAKE_BUILD_TYPE=Debug,然后CMAKE_CXX_FLAGS-g -Wall -Wextra

我尝试以下

message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") 

set(CMAKE_CXX_FLAGS "-O3 -Wall -Wextra") 
set(CMAKE_CXX_FLAGS_DEBUG "-g -Wall -Wextra") 

但这有一个大问题。首先,如果使用第二次调用,则将-O3-g标志传递给编译器。此外,如果我使用第二次调用并且之后的第一次调用,CMAKE_BUILD_TYPE保留Debug,虽然没有明确命令 - 所以我得到一个调试版本,虽然我想要一个优化版本。

为什么?我能做些什么来获得理想的行为?

回答

10

首先:CMake的推荐使用是始终在命令行上明确指定CMAKE_BUILD_TYPE(当且仅当使用单配置生成器时)。你的用例偏离了这个最佳实践,所以把这个答案当作“你怎么做到的”,不一定是“你应该怎么做”。

为了解决第一个问题,你应该能够做到在您的CMakeList早期:

if(NOT CMAKE_BUILD_TYPE) 
    set(CMAKE_BUILD_TYPE Release) 
endif() 

set(CMAKE_CXX_FLAGS "-Wall -Wextra") 
set(CMAKE_CXX_FLAGS_DEBUG "-g") 
set(CMAKE_CXX_FLAGS_RELEASE "-O3") 

这将确保,如果你没有在所有指定生成类型,它会默认为“释放“,因此将使用CMAKE_CXX_FLAGS_RELEASE

第二个难以解决。在命令行(如CMAKE_BUILD_TYPE=Debug)传递的变量是由CMake的缓存并且因此在以后的调用重新使用(即是必要的,因为CMake的可重新触发本身如果修改它的输入构建之间)。

唯一的解决方案是让用户使用cmake .. -DCMAKE_BUILD_TYPE=Release再次明确地切换构建类型。如果CMake的输入(CMakeLists.txt文件或它们的依赖关系)自上次CMake运行以来发生了变化,那么CMake可以重新触发自己作为构建的一部分。在这种情况下,它也将在没有命令行参数(如-DCMAKE_BUILD_TYPE=whatever)的情况下运行,并且将依靠缓存提供与上次相同的值。这种情况与您手动运行cmake ..时无法区分,无需其他参数。

如果没有在命令行中明确指定,我可以提供一个hacky解决方案来始终将CMAKE_BUILD_TYPE重设为Release。然而,这也意味着一个构建系统产生的Debug将得到重新生成作为Release如果自动重新生成发生。我很确定那不是你想要的。

+0

这工作,直到我进行调试构建。在一个调试版本之后,即使使用'cmake ..',所有后续版本都是调试版本 – marmistrz

+0

我不记得我在哪里读过它,但从CMakeLists.txt中设置CMAKE_BUILD_TYPE被认为是不好的做法。喜欢从CMake命令行传递它。 – roalz

+0

@marmistrz我已经添加了为什么发生这种情况的更新,以及如何“重置”它。我试图想出一种实现隐式重置的方法,但这并不容易。 – Angew

4

对于具体的发行对象CXX标志,你应该设置
CMAKE_CXX_FLAGS_RELEASE而不是

CMAKE_CXX_FLAGS

你的情况,你可以使用:

集(CMAKE_CXX_FLAGS“-Wall -Wextra “)
set(CMAKE_CXX_FLAGS_DEBUG”-g“)
set(CMAKE_CXX_FLAGS_RELEASE”-O3“)

一个更现代的CMake的做法(我建议,如果你正在使用CMake的版本2.8.12或更高版本),在this StackOverflow answer有很好的描述,涉及使用target_compile_options

+0

我会说“-g -O0”。 –

+0

但是当'cmake ..' – marmistrz

+1

@ n.m时,'-O3'不会传递给编译器。 gcc默认不会优化 – marmistrz