CMake:将add_library与许多源一起使用并在target_link_libraries中使用时出现链接错误

时间:2019-01-20 03:07:06

标签: cmake linker-errors

最后包括完整列表,此处为特定部分:

add_library(common common.h utils.h utils.cc)


add_executable(type_test type_test.cc)
target_link_libraries(type_test
        ${GTEST_BOTH_LIBRARIES}
        ast
        common
        compilation_context
        easyloggingpp
        functions
        lexer
        parser
        ${CMAKE_THREAD_LIBS_INIT})
add_test(type_test COMMAND out/type_test)

现在,当我运行cmake . --GNinja并随后运行ninja type_test时,我得到:


    [0/1] Re-running CMake...
    -- Found LLVM 6.0.1
    -- Using LLVMConfig.cmake in: /usr/lib/llvm-6.0/cmake
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/gru/Code/schwifty
    [1/1] Linking CXX executable out/type_test
    FAILED: out/type_test 
    : && /usr/bin/clang++  -DELPP_FEATURE_CRASH_LOG   CMakeFiles/type_test.dir/type_test.cc.o  -o out/type_test  /usr/local/lib/libgtest.a /usr/local/lib/libgtest_main.a out/libast.a out/libcommon.a out/libcompilation_context.a out/libeasyloggingpp.a out/libfunctions.a out/liblexer.a out/libparser.a -lpthread && :
    /usr/bin/ld: out/libcompilation_context.a(type.cc.o): in function `schwifty::Types::parse_type_string_internal(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
    type.cc:(.text+0x18cb): undefined reference to `schwifty::utils::startswith(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
    /usr/bin/ld: type.cc:(.text+0x1c04): undefined reference to `schwifty::utils::startswith(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    ninja: build stopped: subcommand failed.

schwifty::utils::startswith肯定在utils.h中声明,并在utils.cc中实现。

此处提供完整列表:


    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)

    find_package(Threads)

    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
            ${CMAKE_THREAD_LIBS_INIT})
    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
            ${CMAKE_THREAD_LIBS_INIT})
    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
            ${CMAKE_THREAD_LIBS_INIT})
    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
            ${CMAKE_THREAD_LIBS_INIT})
    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
            ${CMAKE_THREAD_LIBS_INIT})
    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://bitbucket.org/gruszczy/schwifty/src/default/

2 个答案:

答案 0 :(得分:1)

使用bfd ld的静态库的链接顺序很重要。 (不确定黄金)。在libcompilation_context.a被带到libcommon.a之前,需要读取,处理和删除libcommon.a。

解决此问题的旧方法是ld c.o -lcommon -lcompilation_context -lcommoncmake的{​​{1}}应该(我认为)可以解决您的问题。

答案 1 :(得分:1)

似乎您没有遵循现代CMake最佳实践。您的库不链接任何东西,只有可执行文件链接。手工编译时,这就是这样做的方式,因为静态库不链接到其他静态库,只有可执行文件可以。但是,在CMake中,世界的工作方式有所不同。

您应该始终链接到使用的库,并且直接使用的库,间接使用的库。适用于可执行文件和库目标。 CMake中的目标形成库和可执行文件的层次结构。 CMake跟踪需要什么并相应地链接。例如,如果可执行文件exe需要库liba,而库本身需要库libb,则不应将可执行文件同时链接到libalibbliba链接到libb,仅将可执行文件链接到liba。 CMake将完成剩下的工作,并解析层次结构以形成正确的链接命令。