LINUX.ORG.RU

CMakeLists.txt

 , ,


0

1

Есть проект, результатом которого должны быть две статические библиотеки. Дерево проекта выглядит так:

.
├── CMakeLists.txt
├── base
│   ├── CMakeLists.txt
│   ├──── base.h
│   └──── base.cpp
├── Test1
│   ├── CMakeLists.txt
│   │       └────  set(PROJ1 test1)
│   │              project(${PROJ1})
│   │              set(HDRSRT ../base/base.h test1.h)
│   │              set(SRCSRT ../base/base.cpp test1.cpp)
│   │              find_package(Qt5Core)
│   │              set(CMAKE_AUTOMOC ON)
│   │              add_library(${PROJ1} STATIC ${HDSRT} ${SRCSRT})
│   │              target_link_libraries(${PROJ1} Qt5::Core)
│   ├──── test1.h
│   └──── test1.cpp
└── Test2
    ├── CMakeLists.txt
    ├──── test2.h
    └──── test2.cpp

Тесты имеют общий базовый класс, base. Проект успешно собирается, и, даже работает. Но, если я пробую использовать две библиотеки олдновременно, получаю ошибку multiple definition методов базового класса. Подскажите, пожалуйста, как исправить ситуацию.

★★

Последнее исправление: braboar (всего исправлений: 1)

Ничего не понял, давай с начала. Что значит «пробую использовать две библиотеки одновременно»? Почему сборка таргета делается непонятно где? Где содержимое остальных CMakeLists.txt? Отдельное упоминание всем этим ${PROJ1} – сами CMake’овцы говорят так не делать и просто писать как есть.

Siborgium ★★★★★
()

получаю ошибку multiple definition методов базового класса

Ошибка cmake или c++? Если c++, то проверь наличие директивы #pragma once.

ox55ff ★★★★★
()
Ответ на: комментарий от Siborgium

${PROJ1} – сами CMake’овцы говорят так не делать

Тоже так делаю. Пусть нахер идут. Дублирование констант путь к ошибкам.

ox55ff ★★★★★
()

ты влинковал в две либы один и тот же базовый класс… и чего хочешь-то?

теперь код класса в обоих либах. делай например третью либу с базовым классом, а в две других не линкуй его. пусть они используют эту третью либу

alysnix ★★★
()
Ответ на: комментарий от ox55ff

Покажешь в посте дублирование констант? Даже с учетом скидки на псевдокод, в современном CMake дублировать константы практически не нужно, все заворачивается в таргеты.

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

От базового классе наследуются несколько тестов. В конечной программе возможно использование нескольких тестов и вот там я и получаю multiple definition. Для test2 CMakeLists.txt аналогичный.

braboar ★★
() автор топика
Ответ на: комментарий от ox55ff

Разве линковщик дубли не убьёт?

а может это разные реализации одного класса ? как он убьет?

попробуй в двух разных исходниках реализовать один и тот же метод класса. и линкануть.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от ox55ff

/usr/lib64/gcc/x86_64-suse-linux/9/../../../../x86_64-suse-linux/bin/ld: /home/boris/local/mnt/sda3/work/tests/auxillary/test1/bin/lib/libtest1.a(test1.cpp.o): in function Test1::~Test1()': /home/boris/local/mnt/sda3/work/tests/auxillary/test1/srclib/test1/test1.cpp:10: undefined reference toBase::~Base()’ /usr/lib64/gcc/x86_64-suse-linux/9/../../../../x86_64-suse-linux/bin/ld: /home/boris/local/mnt/sda3/work/tests/auxillary/test1/bin/lib/libtest1.a(mocs_compilation.cpp.o): in function Test1::qt_metacall(QMetaObject::Call, int, void**)': /home/boris/local/mnt/sda3/work/tests/auxillary/test1/buildlib/test1/test1_autogen/EWIEGA46WW/moc_test1.cpp:107: undefined reference toBase::qt_metacall(QMetaObject::Call, int, void**)’ /usr/lib64/gcc/x86_64-suse-linux/9/../../../../x86_64-suse-linux/bin/ld: /home/boris/local/mnt/sda3/work/tests/auxillary/test1/bin/lib/libtest1.a(mocs_compilation.cpp.o): in function Test1::qt_metacast(char const*)': /home/boris/local/mnt/sda3/work/tests/auxillary/test1/buildlib/test1/test1_autogen/EWIEGA46WW/moc_test1.cpp:102: undefined reference toBase::qt_metacast(char const*)’ /usr/lib64/gcc/x86_64-suse-linux/9/../../../../x86_64-suse-linux/bin/ld: /home/boris/local/mnt/sda3/work/tests/auxillary/test1/bin/lib/libtest1.a(mocs_compilation.cpp.o):(.data.rel.ro._ZTI5Test1[_ZTI5Test1]+0x10): undefined reference to typeinfo for Base' /usr/lib64/gcc/x86_64-suse-linux/9/../../../../x86_64-suse-linux/bin/ld: /home/boris/local/mnt/sda3/work/tests/auxillary/test1/bin/lib/libtest1.a(mocs_compilation.cpp.o):(.data.rel.ro+0x0): undefined reference toBase::staticMetaObject’ collect2: error: ld returned 1 exit status gmake[2]: *** [CMakeFiles/testrt.dir/build.make:117: testrt] Error 1 gmake[1]: *** [CMakeFiles/Makefile2:94: CMakeFiles/testrt.dir/all] Error 2 gmake: *** [Makefile:101: all] Error 2 1

braboar ★★
() автор топика
Ответ на: комментарий от alysnix

В том, собственно, и вопрос: как исправить?

braboar ★★
() автор топика
Ответ на: комментарий от braboar

Для test2 CMakeLists.txt аналогичный

Ну вот и разобрались.

Делайте в base

find_package(Qt5Core)
add_library(base)
target_sources(base PUBLIC base.h PRIVATE base.cpp)
target_link_libraries(base PRIVATE Qt5::Core)

а в Test1 и Test2 делайте

target_link_libraries(test1 PRIVATE base)
Siborgium ★★★★★
()
Последнее исправление: Siborgium (всего исправлений: 1)
Ответ на: комментарий от ox55ff

Виноват, пробовал несколько вариантов, напутал.

braboar ★★
() автор топика

Но, если я пробую использовать две библиотеки олдновременно, получаю ошибку multiple definition методов базового класса

А под «собрать одновлеменно» ты не подразумеваешь, случаем, линковку обеих либ в какой-то единый бинарник? Если у тебя тесты из Test2 собираются аналогично Test1, то да, так и должно быть, потому что и тот, и тот собирают base.cpp.

Исправить это можно, например, выделив базу в отдельную разделяемую библиотеку и линкуя тесты с ней

XMs ★★★★★
()
Последнее исправление: XMs (всего исправлений: 1)
Ответ на: комментарий от ox55ff

Говорил про multiple definition, а в сообщении undefined reference.

во блин. это совсем другой номер

alysnix ★★★
()
Ответ на: комментарий от braboar

От базового классе наследуются несколько тестов.

ты логику включи. у тебя есть код, который используется в нескольких либах, или даже экзешниках. значит что? значит его надо вынести в отдельную либу и использовать. вот base класс в такую либу и просится.

alysnix ★★★
()
Ответ на: комментарий от alysnix

Такой вариант я тоже пробовал. Но, так как cmake я знаю плохо, и там не сумел получить результат (был бы совсем не против небольшого примера).

braboar ★★
() автор топика
Ответ на: комментарий от braboar
add_library(base SHARED base.cpp base.h)
add_library(test1 STATIC Test1/test1.cpp Test1/test1.h)
add_library(test2 STATIC Test2/test2.cpp Test2/test2.h)
target_link_libraries(test1 base)
target_link_libraries(test2 base)

Qt сам прикрутишь

XMs ★★★★★
()
Последнее исправление: XMs (всего исправлений: 1)
Ответ на: комментарий от braboar

Такой вариант я тоже пробовал.

зачем вот кстати в смейкфайле хидеры давать? они там не нужны. билдер компилирует исходники, и компилятор тащит автоматом все хидеры, проинклуденные в сорсе. если конечно не извращаться, и их инклудить. а то можно и в хидере код писать и не инклудить его, а потом линковать… но это треш

alysnix ★★★
()
Ответ на: комментарий от alysnix

зачем вот кстати в смейкфайле хидеры давать?

Некоторые IDE показывают только те файлы, которые указаны в смейкфайле.

Вроде Qt Creator так делает…

fsb4000 ★★★★★
()
Ответ на: комментарий от alysnix

Я их для красоты сую. Люблю, когда всё указано. Ну и ещё может быть так, что какой-нибудь CMAKE_AUTOMOC не отработает хедер, если он никуда не включается

XMs ★★★★★
()
Последнее исправление: XMs (всего исправлений: 1)
Ответ на: комментарий от fsb4000

Вроде Qt Creator так делает…

ахренеть… хотя вполне возможно. но это лишний мусор. особенно если кмпилятор его вздумает компилить и свалится. хидер не обязан быть компилируемым.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

Тем не менее, криэйтор иногда ооочееень странные вещи вытворяет, приходится долго файл искать. Причем, версии примерно до 4.12 (точно не помню), поменьше таких багов было. Иногда бывает достаточно чистки кеша и перезапуска cmake.

braboar ★★
() автор топика
Ответ на: комментарий от alysnix

и clion также делает, говорит я этот файл парсить не буду так как он не относится ни к одному проекту.

cmake придумали какой-то лясипед типа target_sources чтобы указывать сорцы отдельно, но target_headers нету чтобы всякие ide подхватывали.

bhfq ★★★★★
()
Последнее исправление: bhfq (всего исправлений: 3)

Видимо ты нарушаешь ODR в исходниках.

slovazap ★★★★★
()

надо было использовать autotools

Harald ★★★★★
()
Ответ на: комментарий от Siborgium

Писать proj1 – дублирование, ${PROJ1} – не дублирование, я правильно понял?

Это дичь какая-то. Там же есть какая-то готовая переменная с именем проекта.

anonymous
()
Ответ на: комментарий от Siborgium

Отдельное упоминание всем этим ${PROJ1} – сами CMake’овцы говорят так не делать и просто писать как есть

Это пустая рекомендация. Сначала обоснуй.

Если имя проекта совпадает с именем цели, то почему бы не вынести в переменную?

rumgot ★★★★★
()
Ответ на: комментарий от alysnix

Хедеры нужны для того, чтобы отображались в дереве проекта в списке хедеров как минимум в Qt Creator (про другие не знаю).

rumgot ★★★★★
()
Ответ на: комментарий от bhfq

cmake придумали какой-то лясипед типа target_sources чтобы указывать сорцы отдельно, но target_headers нету чтобы всякие ide подхватывали.

Потому что sources здесь – это файлы, от которых зависит таргет. Ты туда что угодно положить можешь, хоть джипег. И хэдэры тоже, ага

Stil ★★★★★
()
Ответ на: комментарий от rumgot

Сначала обоснуй.

Обосновываю: никаких преимуществ нет, но теперь приходится дополнительно разбираться с убогими CMake’овскими переменными.

Если имя проекта совпадает с именем цели, то почему бы не вынести в переменную?

Как вынос в переменную помогает при совпадении имени проекта с именем цели?

то почему бы не вынести в переменную?

«Не следует множить сущее без необходимости».

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

Речь идет о дублировании, или о том, что вам имена таргетов лень писать?

Речь о том, что писать везде proj или ${PROJ} - это один хрен. А вот писать либо my_best_utility_0 или ${my} - это уже не один.

rumgot ★★★★★
()
Ответ на: комментарий от rumgot

Нет, речь шла о мифическом дублировании при использовании имен таргетов вместо переобозначения их переменными.

Siborgium ★★★★★
()
Ответ на: комментарий от Siborgium

«Не следует множить сущее без необходимости».

Это да.

Как вынос в переменную помогает при совпадении имени проекта с именем цели?

Ну вот например есть проект MyTest0. И Я хочу исполняемый файл тоже с таким именем. Т.е. как минимум, если не будет установки, то это имя нужно в трех местах:

project(MyTest0)
add_executable(MyTest0 main.cpp)
target_link_libraries(MyTest0 Lib0 Lib1 Lib2)

А вот нужно мне переименовать проект. В случае вынесения имени в переменную просто поменял имя и все Да, я знаю про ${PROJECT_NAME} или ${CMAKE_PROJECT_NAME}, можно и их использовать, но если использовать тот же ${PROJ} получается короче. Но тогда вся эта логика применима и к целям, которые не совпадают с именем проекта.

Вот касательно программирования мы говорим, что если есть некоторая повторяющаяся константа, то лучше ее выносить в переменную, а не использовать как есть несколько раз. Но в cmake скрипте тоже свой ЯП, почему бы этот принцип не использовать и здесь?

rumgot ★★★★★
()
Ответ на: комментарий от Siborgium

Нет, речь шла о мифическом дублировании при использовании имен таргетов вместо переобозначения их переменными.

Так дублирование всегда есть. Ты либо обращение к переменной дублируешь, либо ее значение. Или касательно скажем функций: либо ты один и тот же код дублируешь несколько раз, либо выносишь его в функцию и дублируешь уже ее вызов.

Смысл в не том, чтобы дублирование было редко. А чтобы вызов/обращение к дублирующей сущности было кратким.

rumgot ★★★★★
()
Последнее исправление: rumgot (всего исправлений: 1)
Ответ на: комментарий от rumgot

А вот нужно мне переименовать проект

Часто приходится переименовывать проект?

но если использовать тот же ${PROJ} получается короче.

Нет никакого «короче», речь шла про дублирование. Касательно «короче» мое мнение такое: CMake предлагает неймспейсы, так что нужно использовать их, и в рамках неймспейсов использовать короткие имена изначально.

Вот касательно программирования мы говорим, что если есть некоторая повторяющаяся константа, то лучше ее выносить в переменную, а не использовать как есть несколько раз. Но в cmake скрипте тоже свой ЯП, почему бы этот принцип не использовать и здесь?

Потому что один раз переправить скрипт сборки проще, чем разбираться, что во что резолвится и как раскрывается, учитывая при этом кривые и косые правила CMake. В meson никто таким не страдает – а ведь там язык куда более вменяемый.

Siborgium ★★★★★
()
Ответ на: комментарий от alysnix

зачем вот кстати в смейкфайле хидеры давать?

Я добавляю, чтобы они были видны в дереве файлов проекта в IDE.

ox55ff ★★★★★
()
Ответ на: комментарий от anonymous

Там же есть какая-то готовая переменная с именем проекта.

Есть. Даже две, если используешь подпроекты.

ox55ff ★★★★★
()
Ответ на: комментарий от Siborgium

Дублирование плохо, потому что можешь опечататься на одну букву и потом будешь долго искать в чём проблема. С переменными такого не будет. Они связаны: или имя правильное или вообще ничего не работает.

ox55ff ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.