首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用于玩具编程语言的cmake

用于玩具编程语言的cmake
EN

Code Review用户
提问于 2018-06-10 20:45:00
回答 2查看 279关注 0票数 3

我对cmake的经验很少,这是我第一次在项目中使用它。在过去,我使用了一些autotools,最近主要使用了bazel。我希望有一些建议,如何更好地构造代码。例如,在编译过程中,我注意到相同的目标被多次编译,这在理想情况下我想避免。

代码语言:javascript
复制
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)
EN

回答 2

Code Review用户

回答已采纳

发布于 2019-01-20 04:32:55

我绝不是一个专业的CMake用户,我试着遵循最佳实践,并且看过许多关于现代CMake最佳实践的演讲和文章,所以让我们来看看您的CMakeLists。

代码语言:javascript
复制
set(CMAKE_CXX_STANDARD 14)

由于两个不同的原因,人们普遍不赞成这种做法。首先,也是最重要的是,您将为通过add_subdirectory创建或导入的每个目标全局设置此配置。在现代CMake最佳实践中,只要有可能,您都应该倾向于使用target_函数来精确配置需要配置的目标,而不是全局设置它。其次,您不需要直接设置C++标准,而是应该选择需要编译项目并让CMake决定标准的特性。见目标_编译_特性

代码语言:javascript
复制
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DELPP_FEATURE_CRASH_LOG")

与以前一样,请使用target_compile_definitions(mytarget PUBLIC ELPP_FEATURE_CRASH_LOG)

代码语言:javascript
复制
#
# 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模块,用于提取和编译外部依赖项。

代码语言:javascript
复制
include_directories(external/easyloggingpp)
add_library(easyloggingpp external/easyloggingpp/easylogging++.cc)

您将再次使用include_directories进行全局配置,改用target_include_directories。此外,我真的会考虑拆分您的CMakeLists文件,有太多的事情发生了。将项目存储库细分为子目录,每个库一个,然后使用add_subdirectory导入所需的所有库。

代码语言:javascript
复制
find_package(gtest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})

您将再次设置包含全局目录。实际上,您甚至根本不需要设置目录。target_link_libraries比链接做的更多的是<>>。它可能应该换个名字。由于gtest用它的INTERFACE_INCLUDE_DIRECTORIES设置导出了一个目标,所以单独链接(target_link_libraries)来测试设置包含目标的目录。

如果您遵循最佳实践并使用target_函数设置所有配置,那么在库中所需的全部配置应该是唯一的target_link_library,因为所有其他配置(编译器特性,包括目录,.)如果在此库上设置了PUBLICINTERFACE,则会自动进入。正如我所说,target_link_library所做的不仅仅是链接,它的名字非常具有误导性。一个完美的例子是您正在使用的fmt包。您所做的只是find_package(FMT REQUIRED CONFIG)target_link_libraries(mytarget fmt::fmt),使用这个包的其他一切都是由target_link_libraries命令设置的,因为fmt包导出了它自己的所有需求,并通过它的目标包含路径。

我很肯定我错过了一些事情,但我希望这些提示能帮助你开始工作。

票数 2
EN

Code Review用户

发布于 2018-09-09 22:58:04

我没有使用set对源文件进行多次重新编译,而是切换了add_library,现在它构建所有内容的速度要快得多。不再不必要地再次编译同一个文件。

代码语言:javascript
复制
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)
票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/196243

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档