# Требуем CMake не старее версии 3.20. cmake_minimum_required(VERSION 3.20) # Создаём проект на языке C++. project(mmps_homework_1 LANGUAGES CXX) # Используем стандарт C++17. Он нужен хосту для std::filesystem. set(CMAKE_CXX_STANDARD 17) # Запрещаем CMake использовать более старый стандарт. set(CMAKE_CXX_STANDARD_REQUIRED ON) # Отключаем нестандартные расширения конкретного компилятора. set(CMAKE_CXX_EXTENSIONS OFF) # Создаём основную программу. Она ищет и загружает плагины во время выполнения. add_executable(mmps_host src/main.cpp) # Позволяем подключать общий интерфейс как #include "api.hpp". target_include_directories(mmps_host PRIVATE include) # В Linux функции dlopen, dlsym и dlclose могут требовать библиотеку libdl. # В Windows LoadLibraryW/GetProcAddress предоставляются системой, поэтому # дополнительная библиотека для компоновки не нужна. if(UNIX AND NOT APPLE) target_link_libraries(mmps_host PRIVATE ${CMAKE_DL_LIBS}) endif() # Складываем исполняемый файл в build/bin. set_target_properties(mmps_host PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" ) # Функция создаёт один плагин из переданного исходного файла. function(add_mmps_plugin target source) # MODULE означает динамически загружаемый модуль: # DLL в Windows, SO в Linux и DYLIB в macOS. add_library(${target} MODULE ${source}) # Плагину доступны общие структуры, типы функций и имена символов из api.hpp, # а также вспомогательные функции численных методов из state.hpp. target_include_directories(${target} PRIVATE include) # PLUGIN_BUILD включает __declspec(dllexport) при сборке DLL в Windows. # Определение PRIVATE и потому не передаётся другим целям. target_compile_definitions(${target} PRIVATE PLUGIN_BUILD) # PREFIX "" убирает стандартный префикс lib у имени плагина. # Все плагины складываются в общий каталог build/plugins. set_target_properties(${target} PROPERTIES PREFIX "" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/plugins" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/plugins" ) endfunction() # Каждый решатель и способ вывода собирается в отдельную библиотеку. add_mmps_plugin( runge_kutta_plugin plugins/runge_kutta_plugin.cpp ) add_mmps_plugin( adams_bashforth_plugin plugins/adams_bashforth_plugin.cpp ) add_mmps_plugin( console_output_plugin plugins/console_output_plugin.cpp ) add_mmps_plugin( csv_output_plugin plugins/csv_output_plugin.cpp ) # ЧТО ПРОИСХОДИТ ПРИ СБОРКЕ # src/main.cpp -> mmps_host.exe # plugins/runge_kutta_plugin.cpp -> runge_kutta_plugin.dll # plugins/adams_bashforth_plugin.cpp -> adams_bashforth_plugin.dll # plugins/console_output_plugin.cpp -> console_output_plugin.dll # plugins/csv_output_plugin.cpp -> csv_output_plugin.dll # # Хост и плагины собираются независимо. Здесь намеренно нет команд: # target_link_libraries(mmps_host PRIVATE runge_kutta_plugin) # target_link_libraries(mmps_host PRIVATE adams_bashforth_plugin) # # Поэтому в mmps_host не записываются обязательные зависимости от конкретных # решателей. При запуске хост просматривает заданный каталог, загружает каждый # подходящий файл через LoadLibraryW/dlopen и ищет функции по контракту api.hpp. # Добавление ещё одного совместимого решателя не требует изменения main.cpp. # # ПРИМЕР СБОРКИ # cmake -S . -B build # cmake --build build --config Release # # ПРИМЕР ЗАПУСКА ИЗ КАТАЛОГА build # bin/Release/mmps_host.exe (Visual Studio) # bin/mmps_host (Linux/Makefiles)