Компоновщик C находит заголовок, но не может найти .cpp-файл (используя cmake, gcc)

#c #gcc #cmake #linker-errors #undefined-reference

#c #ссагпз #cmake #компоновщик -ошибки #не определено-ссылка

Вопрос:

Я пытаюсь включить проект в проект. Соответствующая структура как таковая:

 projectA
       /CMakeLists.txt (PA1)
       /src
           /main.cpp
       /req/projectB
                   /CMakeLists.txt (PB1)
                   /src
                       /projb.hpp
                       /projb.cpp
                       /CMakeLists.txt (PB2)
 

После компиляции связывание ЗАВЕРШИТСЯ УСПЕШНО, если я закомментирую все в projb.cpp , (и определите его в заголовке), но СБОЙ с неопределенной ссылкой (на любую функцию, определенную в projb.cpp ).

— (PA1)-

 add_subdirectory("req/projectB")

include_directories(${PROJECT_NAME} "req/projectB/src")

add_executable(${PROJECT_NAME} src/main.cpp)
target_link_libraries(${PROJECT_NAME} INTERFACE projectB)
 

— (РБ1)-

 add_subdirectory(src)
 

— (PB2)-

 add_library(projectB projb.hpp projb.cpp)
 

main.cpp

 int main() {
    project_b::doStuff();
    return 1;
}
 

projb.hpp

 namespace project_b {

    void doStuff(); // fails
    
    void doStuff() {} // works if nothing defined in .cpp
    // (only one or the other version is declared not both)

} // end namespace
 

projb.cpp

 namespace project_b {
    
    void doStuff() {} // fails with undefined reference error when called from main

} // end namespace
 

Комментарии:

1. Компоновщик вообще не просматривает .cpp-файлы. Запустите make VERBOSE=1 , чтобы увидеть фактические команды компиляции.

2. вот как я запускал make

3. Это не видно из вашего сообщения. Если projb.cpp не компилируется, почему удивительно, что материал, определенный в нем, не определен?

4. когда я проверяю папку сборки, библиотеки для ProjectB находятся там.

5. Но они не используются для сборки исполняемого файла

Ответ №1:

Оказывается, что другая часть ProjectA, которую я считал неактуальной, на самом деле была очень актуальной.

Таким образом, мне просто нужно было добавить эту строку:

 # projAadep is included by main.cpp from projectA
target_link_libraries(projAdep PRIVATE projectB)
 

перед этой строкой:

 target_link_libraries(${PROJECT_NAME} PUBLIC projectB)
 

Мое понимание заключалось в том, что с помощью:

 target_link_libraries(${PROJECT_NAME} list of all used libs here)
 

было все, что необходимо.

Как это было обнаружено, когда я комментировал различные вещи, чтобы получить вывод make VERBOSE=1 , содержащий только наиболее релевантные части, он успешно скомпилирован и связан. Затем это заставило меня провести дополнительное тестирование, чтобы выяснить, почему он успешно связан, и так далее.

Ответ №2:

Библиотеки, следующие за ИНТЕРФЕЙСОМ, добавляются к интерфейсу ссылки и не используются для компоновки .

смотрите: https://cmake.org/cmake/help/latest/command/target_link_libraries.html

Итак, я предлагаю изменить ИНТЕРФЕЙС на ОБЩЕДОСТУПНЫЙ или ЧАСТНЫЙ

Комментарии:

1. пробовал использовать ОБЩЕДОСТУПНЫЕ и ЧАСТНЫЕ, но все равно не работает

2. @R.Smyth Работает на меня, возможно, раскомментирует projb.cpp ?

3. так оно и есть. все еще терпит неудачу.

4. @R.Smyth пожалуйста, опубликуйте полный вывод make VERBOSE=1 .

5. Кроме того, удалите CMakeCache.txt и выполните make clean перед сборкой.