我对cmake的经验很少,这是我第一次在项目中使用它。在过去,我使用了一些autotools,最近主要使用了bazel。我希望有一些建议,如何更好地构造代码。例如,在编译过程中,我注意到相同的目标被多次编译,这在理想情况下我想避免。
cmake_minimum_required(VERSION 3.10)
project(schwifty)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DELPP_FEATURE_CRASH_LOG")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out)
find_package(PythonInterp 3.6 REQUIRED)
file(MAKE_DIRECTORY downloads external)
################################################################################
# Easylogging++
################################################################################
if(EXISTS "external/easyloggingpp")
else()
file(MAKE_DIRECTORY external/easyloggingpp)
file(DOWNLOAD
https://github.com/muflihun/easyloggingpp/archive/v9.96.4.zip
downloads/easyloggingpp.zip)
execute_process(COMMAND unzip downloads/easyloggingpp.zip -d downloads)
file(GLOB easyloggingpp_files downloads/easyloggingpp-9.96.4/src/easylogging++.*)
file(COPY ${easyloggingpp_files} DESTINATION external/easyloggingpp)
endif()
set(ast ast.h ast.cc)
set(codegen codegen.h codegen.cc)
set(functions functions.h functions.cc)
set(parser parser.h parser.cc)
include_directories(external/easyloggingpp)
set(easyloggingpp external/easyloggingpp/easylogging++.cc)
set(SOURCE_FILES
ast_compare_visitor.cc
ast_compare_visitor.h
classes.cc
classes.h
compilation_context.cc
compilation_context.h
common.h
errors.h
errors.cc
expression_type_visitor.cc
expression_type_visitor.h
functions.cc
functions.h
jit.cc
jit.h
lexer.cc
lexer.h
lexer_common.cc
lexer_common.h
runtime.h
runtime.cc
utils.h
utils.cc
type.cc
type.h
type_inference_visitor.cc
type_inference_visitor.h
enum.cc
enum.h
type_inference.cc
type_inference.h
operators.cc
operators.h
symbol_visitor.cc
symbol_visitor.h)
add_library(sources ${SOURCE_FILES})
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(llvm_libs all)
find_package(FMT REQUIRED CONFIG)
add_executable(schwifty
schwifty.cc
${ast}
${codegen}
${easyloggingpp}
${parser})
target_link_libraries(schwifty ${llvm_libs})
target_link_libraries(schwifty fmt::fmt)
target_link_libraries(schwifty sources)
################################################################################
# Testing
################################################################################
enable_testing()
find_package(gtest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})
add_executable(codegen_test codegen_test.cc ${ast} ${codegen} ${easyloggingpp}
${functions} ${parser})
target_link_libraries(codegen_test ${GTEST_BOTH_LIBRARIES})
target_link_libraries(codegen_test ${llvm_libs})
target_link_libraries(codegen_test fmt::fmt)
target_link_libraries(codegen_test sources)
add_test(codegen_test COMMAND out/codegen_test)
add_executable(lexer_test lexer_test.cc ${ast} ${codegen} ${easyloggingpp}
${functions} ${parser})
target_link_libraries(lexer_test ${GTEST_BOTH_LIBRARIES})
target_link_libraries(lexer_test ${llvm_libs})
target_link_libraries(lexer_test fmt::fmt)
target_link_libraries(lexer_test sources)
add_test(lexer_test COMMAND out/lexer_test)
add_executable(parser_test parser_test.cc ${ast} ${codegen} ${easyloggingpp}
${functions} ${parser})
target_link_libraries(parser_test ${GTEST_BOTH_LIBRARIES})
target_link_libraries(parser_test ${llvm_libs})
target_link_libraries(parser_test fmt::fmt)
target_link_libraries(parser_test sources)
add_test(parser_test COMMAND out/parser_test)
add_executable(type_test type_test.cc ${ast} ${codegen} ${easyloggingpp}
${functions} ${parser})
target_link_libraries(type_test ${GTEST_BOTH_LIBRARIES})
target_link_libraries(type_test ${llvm_libs})
target_link_libraries(type_test fmt::fmt)
target_link_libraries(type_test sources)
add_test(type_test COMMAND out/type_test)
add_executable(type_inference_test type_inference_test.cc ${ast} ${codegen}
${easyloggingpp} ${functions} ${parser})
target_link_libraries(type_inference_test ${GTEST_BOTH_LIBRARIES})
target_link_libraries(type_inference_test ${llvm_libs})
target_link_libraries(type_inference_test fmt::fmt)
target_link_libraries(type_inference_test sources)
add_test(type_inference_test COMMAND ./out/type_inference_test)
add_test(NAME end_to_end_tests WORKING_DIRECTORY ${CTEST_SOURCE_DIRECTORY}
COMMAND ${PYTHON_EXECUTABLE} ${CTEST_SOURCE_DIRECTORY}/end_to_end_tests.py)发布于 2019-01-20 04:32:55
我绝不是一个专业的CMake用户,我试着遵循最佳实践,并且看过许多关于现代CMake最佳实践的演讲和文章,所以让我们来看看您的CMakeLists。
set(CMAKE_CXX_STANDARD 14)由于两个不同的原因,人们普遍不赞成这种做法。首先,也是最重要的是,您将为通过add_subdirectory创建或导入的每个目标全局设置此配置。在现代CMake最佳实践中,只要有可能,您都应该倾向于使用target_函数来精确配置需要配置的目标,而不是全局设置它。其次,您不需要直接设置C++标准,而是应该选择需要编译项目并让CMake决定标准的特性。见目标_编译_特性。
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DELPP_FEATURE_CRASH_LOG")与以前一样,请使用target_compile_definitions(mytarget PUBLIC ELPP_FEATURE_CRASH_LOG)
#
# Easylogging++
#
if(EXISTS "external/easyloggingpp")
else()
file(MAKE_DIRECTORY external/easyloggingpp)
file(DOWNLOAD https://github.com/muflihun/easyloggingpp/archive/v9.96.4.zip
downloads/easyloggingpp.zip)
execute_process(COMMAND unzip downloads/easyloggingpp.zip -d downloads)
file(GLOB easyloggingpp_files
downloads/easyloggingpp-9.96.4/src/easylogging++.*)
file(COPY ${easyloggingpp_files} DESTINATION external/easyloggingpp)
endif()这看上去像是一次杂乱无章的黑客攻击,让人产生依赖性。如果这个依赖项是必需的来构建您的项目,那么您可能应该将它作为一个子存储库添加到您自己的git源存储库中,并使用add_subdirectory (假设它是一个CMake项目)。或者,也有存在于此唯一原因的ExternalProject模块,用于提取和编译外部依赖项。
include_directories(external/easyloggingpp)
add_library(easyloggingpp external/easyloggingpp/easylogging++.cc)您将再次使用include_directories进行全局配置,改用target_include_directories。此外,我真的会考虑拆分您的CMakeLists文件,有太多的事情发生了。将项目存储库细分为子目录,每个库一个,然后使用add_subdirectory导入所需的所有库。
find_package(gtest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})您将再次设置包含全局目录。实际上,您甚至根本不需要设置目录。target_link_libraries比链接做的更多的是<>>。它可能应该换个名字。由于gtest用它的INTERFACE_INCLUDE_DIRECTORIES设置导出了一个目标,所以单独链接(target_link_libraries)来测试设置包含目标的目录。
如果您遵循最佳实践并使用target_函数设置所有配置,那么在库中所需的全部配置应该是唯一的target_link_library,因为所有其他配置(编译器特性,包括目录,.)如果在此库上设置了PUBLIC或INTERFACE,则会自动进入。正如我所说,target_link_library所做的不仅仅是链接,它的名字非常具有误导性。一个完美的例子是您正在使用的fmt包。您所做的只是find_package(FMT REQUIRED CONFIG)和target_link_libraries(mytarget fmt::fmt),使用这个包的其他一切都是由target_link_libraries命令设置的,因为fmt包导出了它自己的所有需求,并通过它的目标包含路径。
我很肯定我错过了一些事情,但我希望这些提示能帮助你开始工作。
发布于 2018-09-09 22:58:04
我没有使用set对源文件进行多次重新编译,而是切换了add_library,现在它构建所有内容的速度要快得多。不再不必要地再次编译同一个文件。
cmake_minimum_required(VERSION 3.10)
project(schwifty)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DELPP_FEATURE_CRASH_LOG")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out)
find_package(PythonInterp 3.6 REQUIRED)
file(MAKE_DIRECTORY downloads external)
#
# Easylogging++
#
if(EXISTS "external/easyloggingpp")
else()
file(MAKE_DIRECTORY external/easyloggingpp)
file(DOWNLOAD https://github.com/muflihun/easyloggingpp/archive/v9.96.4.zip
downloads/easyloggingpp.zip)
execute_process(COMMAND unzip downloads/easyloggingpp.zip -d downloads)
file(GLOB easyloggingpp_files
downloads/easyloggingpp-9.96.4/src/easylogging++.*)
file(COPY ${easyloggingpp_files} DESTINATION external/easyloggingpp)
endif()
include_directories(external/easyloggingpp)
add_library(easyloggingpp external/easyloggingpp/easylogging++.cc)
#
# Local lib targets
#
add_library(ast ast.h ast.cc)
add_library(ast_compare_visitor ast_compare_visitor.h ast_compare_visitor.cc)
add_library(classes classes.h classes.cc)
add_library(codegen
codegen.h
codegen.cc
codegen_common.h
codegen_common.cc
expression_type_visitor.cc
expression_type_visitor.h)
add_library(common common.h utils.h utils.cc)
add_library(compilation_context
compilation_context.h
compilation_context.cc
enum.h
enum.cc
errors.h
errors.cc
operators.h
operators.cc
type.h
type.cc)
add_library(functions functions.h functions.cc)
add_library(jit jit.cc jit.h)
add_library(lexer lexer.cc lexer.h lexer_common.cc lexer_common.h)
add_library(parser parser.h parser.cc)
add_library(runtime runtime.cc runtime.h)
add_library(type_inference
type_inference.h
type_inference.cc
symbol_visitor.cc
symbol_visitor.h
type_inference_visitor.cc
type_inference_visitor.h)
#
# External lib targets
#
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
llvm_map_components_to_libnames(llvm_libs all)
find_package(FMT REQUIRED CONFIG)
#
# Schwifty main executable
#
add_executable(schwifty schwifty.cc)
target_link_libraries(schwifty
${llvm_libs}
ast
classes
codegen
common
compilation_context
easyloggingpp
fmt::fmt
functions
lexer
parser
runtime
type_inference)
#
# Testing
#
enable_testing()
find_package(gtest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})
add_executable(codegen_test codegen_test.cc)
target_link_libraries(codegen_test
${GTEST_BOTH_LIBRARIES}
${llvm_libs}
easyloggingpp
ast
classes
codegen
common
compilation_context
fmt::fmt
functions
jit
lexer
parser
runtime
type_inference)
add_test(codegen_test COMMAND out/codegen_test)
add_executable(lexer_test lexer_test.cc)
target_link_libraries(lexer_test
${GTEST_BOTH_LIBRARIES}
ast
common
compilation_context
easyloggingpp
functions
lexer
parser
fmt::fmt)
add_test(lexer_test COMMAND out/lexer_test)
add_executable(parser_test parser_test.cc)
target_link_libraries(parser_test
${GTEST_BOTH_LIBRARIES}
ast
ast_compare_visitor
compilation_context
common
easyloggingpp
functions
lexer
parser
fmt::fmt)
add_test(parser_test COMMAND out/parser_test)
add_executable(type_test type_test.cc)
target_link_libraries(type_test
${GTEST_BOTH_LIBRARIES}
ast
common
compilation_context
easyloggingpp
functions
lexer
parser)
add_test(type_test COMMAND out/type_test)
add_executable(type_inference_test type_inference_test.cc)
target_link_libraries(type_inference_test
${GTEST_BOTH_LIBRARIES}
easyloggingpp
ast
classes
common
compilation_context
functions
fmt::fmt
lexer
parser
runtime
type_inference)
add_test(type_inference_test COMMAND ./out/type_inference_test)
add_test(NAME end_to_end_tests
WORKING_DIRECTORY ${CTEST_SOURCE_DIRECTORY}
COMMAND ${PYTHON_EXECUTABLE} end_to_end_tests.py)https://codereview.stackexchange.com/questions/196243
复制相似问题