CMake: ошибка связывания при использовании add_library со многими источниками и использовании его в target_link_libraries - PullRequest
0 голосов
/ 20 января 2019

Полный список включен в конце, здесь конкретные части:

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 голосов
/ 20 января 2019

Похоже, вы не следуете современным рекомендациям CMake.Ваши библиотеки не ссылаются ни на что, только ваши исполняемые файлы.При компиляции вручную это делается так, потому что статические библиотеки не ссылаются на другие статические библиотеки, а только исполняемые файлы.Однако в CMake мир работает немного по-другому.

Вы всегда должны ссылаться на библиотеки, которые вы используете, и только , которые вы используете напрямую, не , что вы косвенно использовать.Как для исполняемых, так и для библиотечных целей.Цели в CMake образуют иерархию библиотек и исполняемых файлов.CMake отслеживает, что нужно, и ссылки соответственно.Например, если для вашего исполняемого файла exe требуется библиотека liba, которая сама требует библиотеки libb, вы НЕ должны связывать свой исполняемый файл с liba и libb, а вместо этого связывать liba с libb и толькосвяжите ваш исполняемый файл с liba.CMake сделает все остальное и разрешит иерархию для формирования правильной команды компоновки.

0 голосов
/ 20 января 2019

Связывание порядка имеет значение для статических библиотек с помощью bfd ld. (не уверен насчет золота). libcommon.a читается, обрабатывается и сбрасывается до того, как libcompilation_context.a возвращается, для чего нужны символы, объявленные в libcommon.a.

Старый способ исправить это был ld c.o -lcommon -lcompilation_context -lcommon. cmake * LINK_INTERFACE_MULTIPLICITY должен (я думаю) решить вашу проблему.

...