@amorphine

Может ли код(определение) в заголовочных файлах быть вынесен в shared library?

Имеется такая библиотека
И объявления и определения находятся в одном файле.
При попытке скомпилировать как shared, создается so-файл размером примерно 7 кбайт, но при ldd показывает, что искомая shared-библиотека не линкуется, а размер исполняемого файла говорит, что библиотека линкуется статически.

Правильно ли я понимаю, что код в h-файлах инклюдится и компилируется вместе с исполняемым файлом и чтобы вынести в shared нужно:
  • создавать промежуточную cpp/h-пустышку, куда включать csv.h
  • переписать h в h/cpp


cmake
cmake_minimum_required(VERSION 3.7.2)
project(csvp)

option(BUILD_SHARED_LIBS "build as shared library" ON)
set(CMAKE_CXX_STANDARD 11)

find_package (Threads)

include_directories(libs/tinyxml2)
include_directories(libs/tclap/include)
include_directories(libs/csv)

set(SOURCE_FILES main.cpp)
add_executable(csvp ${SOURCE_FILES})

add_subdirectory(libs/tinyxml2)

add_library(tclap SHARED libs/tclap/include/tclap/CmdLine.h)
set_target_properties(tclap PROPERTIES LINKER_LANGUAGE CXX)

add_library(csv SHARED libs/csv/csv.h)
set_target_properties(csv PROPERTIES LINKER_LANGUAGE CXX)

add_library(csvparser SHARED libs/csv-parser/csv_parser.cpp)
set_target_properties(csv PROPERTIES LINKER_LANGUAGE CXX)

target_link_libraries (csvp ${CMAKE_THREAD_LIBS_INIT} tinyxml2 csv tclap csvparser)


ldd

ldd csvp
        linux-vdso.so.1 =>  (0x00007fff8fd48000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f41922fb000)
        libtinyxml2d.so.5 => /var/www/pprc_csv2xml_cpp/cmake-build-debug/libs/tinyxml2/libtinyxml2d.so.5 (0x00007f41920de000)
        libcsvparser.so => /var/www/pprc_csv2xml_cpp/cmake-build-debug/libcsvparser.so (0x00007f4191ed9000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f4191b57000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f4191940000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4191576000)
        /lib64/ld-linux-x86-64.so.2 (0x0000558538071000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f419126d000)


Для примера добавил в сборку аналогичный проект(назвал таргет csvparser, в котором есть h/cpp), он компилится в нормальную shared-lib, видно из ldd.

Впервые пишу на CPP, просто оцениваю порог вхождения.
  • Вопрос задан
  • 211 просмотров
Решения вопроса 2
@Mercury13
Программист на «си с крестами» и не только
Надо сделать CPP-файл, в которые перенести как можно больше кода из программы. И код производят:
• Static- и глобальные переменные.
• Нешаблонные, не-inline-функции.
• Не-inline, полностью расшаблоненные функции template<>.
• Не-extern объявление шаблона типа template class std::vector<int>.
Мало того, эти четыре вещи ошибочно держать в хедерах — но этого, как ни странно, в нашей библиотеке и нет, ведь она полностью полагается на шаблоны. Но есть пара резервов.

1. Функция в теле класса автоматически становится inline, и, я бы сказал, что-нибудь типа AsynchronousReader::init было бы ошибкой держать inline’ом. По-хорошему, его надо в CPP. Но это довольно небольшая часть кода.
2. Можно также наиболее распространённые версии классов/функций залить в SO. Для этого их надо вынести из тел классов и поступить примерно так.
// H
template <int x>
void foo () { std::cout << x << std::endl; }

extern template void foo<2>();

// CPP
template void foo<2>();
Ответ написан
Комментировать
@MarkusD Куратор тега C++
все время мелю чепуху :)
У C++ есть понятие Translation Unit. Как видишь, это 7я фаза трансляции, слияние всех .h файлов происходит на 4й фазе.
.h файлы не являются единицами трансляции по своей семантике.

В идеале, библиотека "fast-cpp-csv-parser" потому и выполнена в виде header-only, что она fast, используется по ее месту и не подразумевает за собой дополнительных единиц трансляции. Ее незачем выводить в динамическую библиотеку.

Но если, скажем, тебе очень надо, то можно сделать так.
Нужно объявить общий интерфейс взаимодействия между кодом процесса и кодом библиотеки (набор функций или интерфейс, по вкусу). В рамках единицы трансляции твоей динамической библиотеки, и вне этого общего интерфейса, надо подключить и задействовать "fast-cpp-csv-parser". Конкретная реализация общего интерфейса взаимодействия внутри твоей динамической библиотеки должна использовать код "fast-cpp-csv-parser".
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы