[FEATURE] Deploying tools built against the developer SDK: openms_install_runtime(), third-party licenses in the SDK, and a deployment check
Los mantenedores suelen responder en 1 día
@kg290 ya está trabajando en esto.
Desde el 1/10/2026.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 35/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- cmake, cpp
- Área
- build-system, devops, release, tooling
Línea de trabajo
Start with cmake/OpenMSDeploy.cmake, the license installation rule in src/openms/CMakeLists.txt, and the existing packaging logic in cmake/package_general.cmake and cmake/package_nsis.cmake. Review tools/ci/package_sdk.sh and the installed-consumer tests to understand the deployment checks. Done means the SDK and installed consumers carry required licenses, install runtime files correctly, and pass deployment checks on all three platforms.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Summary
#10248 ships a relocatable developer SDK per platform, and building a TOPP-style tool against it is a find_package(OpenMS CONFIG REQUIRED COMPONENTS CLI) away. Shipping that tool is still manual, and every step of it is a place to get it subtly wrong. This issue proposes three follow-ups, in order of value and independence:
- Ship the third-party licenses of the bundled libraries in
share/OpenMS/LICENSES. Today the SDK archive (and, for the same reason, the OpenMS installers) bundles roughly 200 third-party libraries but only the OpenMS BSD license text. Anyone who redistributes a tool built on the SDK cannot meet the attribution terms of those libraries without collecting the texts by hand. openms_install_runtime(), a CMake function provided by the installed package (find_package(OpenMS)), which turns "install my tool plus everything it needs to run" into one call: the target, the OpenMS libraries and their bundled dependencies,share/OpenMS, the install RPATH, the MSVC runtime on Windows, and optionally re-signing on macOS.- A deployment check in the installed-consumer tests and in the SDK check of
release.yml: deploy the example tool from the extracted SDK, take the SDK away, run the deployed tool with a scrubbed environment. That is the property a user of the helper relies on, so it should be what CI proves on all three platforms.
Motivation: what a deployer has to do today
With the SDK from #10248, a working deployment needs all of the following, and nothing tells the user so except the source of package_sdk.sh and File.cpp:
- Copy the SDK's
lib/(Linux, macOS) orbin/(Windows) next to the tool. The libraries are relocatable ($ORIGIN/@loader_pathRPATHs, DLLs side by side), so copying works, but the directory also holdslib/cmake/, the static archiveslibIsoSpec.aandlibeol-bspline.a, and on Windows the import libraries, none of which belong in a deployment. - Copy
share/OpenMS(about 80 MB, of whichCHEMISTRYis 54 MB andmodels21 MB) to<prefix>/share/OpenMS.File::getOpenMSDataPath()resolves the data directory relative to the executable (../../../share/OpenMS, then../share/OpenMS) before it falls back toOPENMS_DATA_PATH, so this layout works without any environment variable, and a layout that deviates from it fails at the firstFile::find(). - Give the tool an install RPATH (
$ORIGIN/../lib,@executable_path/../lib). CMake strips the build-tree RPATH at install time, so a tool that runs from the build directory dies at startup aftercmake --installunlessINSTALL_RPATHis set. - On Windows, ship the MSVC runtime: the SDK excludes it like every other System32 library, so an installer has to
include(InstallRequiredSystemLibraries)the waycmake/package_nsis.cmakedoes, or require the redistributable. - On macOS, decide about signatures: the SDK's Mach-O files are signed (with the OpenMS identity in releases, ad hoc otherwise;
package_sdk.shre-signs after rewriting install names). Copying keeps those signatures valid, but a notarized distribution needs the distributor's Developer ID on every Mach-O file and the hardened runtime on the executable. - Collect the licenses of the bundled libraries from somewhere else, because the SDK does not carry them (see 1.).
The manual recipe, for reference, is about 15 lines of CMake and gets the size (all of lib/), the RPATH and the licenses wrong unless one knows the above:
find_package(OpenMS CONFIG REQUIRED COMPONENTS CLI)
add_executable(MyTool MyTool.cpp)
target_link_libraries(MyTool PRIVATE OpenMS::OpenMS_CLI)
set_target_properties(MyTool PROPERTIES INSTALL_RPATH "$ORIGIN/../lib") # macOS: @executable_path/../lib
get_filename_component(OPENMS_SDK "${OpenMS_DIR}/../../.." ABSOLUTE)
install(TARGETS MyTool RUNTIME DESTINATION bin)
install(DIRECTORY "${OPENMS_SDK}/lib/" DESTINATION lib) # Windows: bin/, DLLs only
install(DIRECTORY "${OPENMS_SDK}/share/" DESTINATION share)
include(CPack)
With this issue done, the same deployment is:
find_package(OpenMS CONFIG REQUIRED COMPONENTS CLI)
add_executable(MyTool MyTool.cpp)
target_link_libraries(MyTool PRIVATE OpenMS::OpenMS_CLI)
openms_install_runtime(TARGETS MyTool)
include(CPack)
Goals and non-goals
Goals:
- A tool built against the SDK (or against a
cmake --installprefix of OpenMS) can be installed and packaged with one function call, on Linux, macOS and Windows, producing a tree that runs on a machine without OpenMS, without the SDK and without environment variables. - The deployed tree carries the license texts its contents require.
- CI proves both, on every platform, from the SDK the release workflow produces.
Non-goals:
- The GUI layer (
OpenMS::OpenMS_GUI, Qt): the SDK does not ship it, and Qt deployment (plugins, frameworks,macdeployqt/windeployqt) is a different problem. - macOS
.appbundles and notarization: the helper can re-sign, the distributor notarizes with their own account, as OpenMS does for its own installer. - pyOpenMS.
Design
1. Third-party licenses in share/OpenMS/LICENSES
Current state: src/openms/CMakeLists.txt installs License.txt as share/OpenMS/LICENSES/OpenMS-BSD-3-Clause.txt (component share); cmake/cmake_findExternalLibs.cmake adds the Thermo RawFileReader license for a WITH_THERMO_RAW build. Nothing else. The release artifacts (installers and SDK) are built with vcpkg, and vcpkg installs a copyright file for every port under <vcpkg_installed>/<triplet>/share/<port>/copyright; that is the source of truth to ship.
Proposal:
- A new
cmake/install_third_party_licenses.cmake, included fromsrc/openms/CMakeLists.txtnext to the existing license rule. WhenVCPKG_INSTALLED_DIRandVCPKG_TARGET_TRIPLETare set (vcpkg build), it globs${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/share/*/copyright, skips thevcpkg-*helper ports, and installs each file asshare/OpenMS/LICENSES/<port>.txtin thesharecomponent.shareis the right component: the installers, the deb and the SDK all contain it, andshare/OpenMS/LICENSESis where the existing license lives. The trade-off of "every port in the install tree" versus "only the ports whose libraries were actually bundled" is deliberate: computing the latter needs the runtime-dependency closure at configure time, and a few superfluous license texts (a few hundred KB in total) are cheaper than a missing one. - Non-vcpkg builds (contrib submodule, conda-forge, distribution packages) get a
message(STATUS)that third-party licenses were not collected, and nothing else. Their dependencies come from the system or from conda, which carry their own license files. cmake/OpenMSSDKReadme.txtgets a "Licenses" section: what is undershare/OpenMS/LICENSES, and that a redistributed tool has to carry that directory (whichopenms_install_runtime()does by copyingshare/OpenMS).tools/ci/package_sdk.shchecks, when the build tree's cache holdsVCPKG_INSTALLED_DIR, thatshare/OpenMS/LICENSESin the archive holds more than the OpenMS license, and fails otherwise.
This part is independent of the rest, fixes the same gap in the installers, and should be its own PR.
2. openms_install_runtime() in OpenMSDeploy.cmake
Placement: cmake/OpenMSDeploy.cmake in the sources, installed by cmake/export_macros.cmake next to OpenMSConfig.cmake (component cmake, so it is in the SDK and in every cmake --install prefix), and included at the end of cmake/OpenMSConfig.cmake.in. find_package(OpenMS) then provides the function; consumers include nothing extra.
API:
openms_install_runtime(
TARGETS <target>... # your executables (and shared libraries)
[BIN_DESTINATION <dir>] # where the targets go; default bin
[LIB_DESTINATION <dir>] # where the OpenMS libraries go; default lib (Windows: BIN_DESTINATION)
[SHARE_DESTINATION <dir>] # where share/OpenMS goes; default share
[COMPONENT <name>] # install component of everything installed here; default Runtime
[NO_SHARE] # do not install share/OpenMS
[NO_MODELS] # install share/OpenMS without models/ (21 MB; only PeptDeep users need it)
[NO_SYSTEM_RUNTIME] # Windows: do not include(InstallRequiredSystemLibraries)
[RESOLVE_DEPENDENCIES] # copy only the libraries the targets load (see below)
[SIGNING_IDENTITY <identity>] # macOS: re-sign every installed Mach-O file with this identity
)
What it does:
install(TARGETS <targets> RUNTIME DESTINATION <bin> LIBRARY DESTINATION <lib> COMPONENT <component>).- Sets
INSTALL_RPATHon each target that does not set one, computed from the two destinations:$ORIGIN/<relative path from bin to lib>on Linux,@executable_path/...(executables) or@loader_path/...(shared libraries) on macOS. Nothing on Windows. - Installs the OpenMS runtime libraries into
<lib>:- For an SDK (see 3.),
install(DIRECTORY "${OPENMS_LIB_DIR}/" ...)restricted to shared libraries (*.so*,*.dylib,*.framework; on Windows${OPENMS_BIN_DIR}/*.dll), excludingcmake/, static archives and import libraries. This is correct for an SDK by construction:sdk_prune_dependencies.cmakehas reducedlib/to the runtime closure oflibOpenMS,libOpenSwathAlgoandlibOpenMS_CLI, so there is nothing to resolve and nothing to get wrong, and it needs nodumpbin/otool/objdumpat install time. - For a plain
cmake --installprefix, or withRESOLVE_DEPENDENCIES,install(TARGETS ... RUNTIME_DEPENDENCY_SET openms_runtime)plusinstall(RUNTIME_DEPENDENCY_SET openms_runtime DESTINATION <lib> DIRECTORIES ${OPENMS_LIB_DIR} ${OPENMS_BIN_DIR} PRE_EXCLUDE_REGEXES ... POST_EXCLUDE_REGEXES ...), the mechanism the installers use. In such a prefixlib/holds only the OpenMS libraries and the dependencies live in the system or conda prefixes, so they have to be resolved. The exclusion lists (System32,api-ms-*, MSVC runtime DLLs,/usr/lib,/System/, libc/libstdc++/libgomp on Linux) are the ones incmake/package_general.cmake; factor them intocmake/OpenMSRuntimeExcludes.cmake, installed alongside, so that the installers and the helper cannot drift apart.
- For an SDK (see 3.),
install(DIRECTORY "${OPENMS_DATA_DIR}/" DESTINATION <share>/OpenMS)unlessNO_SHARE; withNO_MODELS,PATTERN "models" EXCLUDE. The function checks that<share>is../sharerelative to<bin>(or../../../share), the two layoutsFile::getOpenMSDataPath()probes, and warns otherwise; the deployed tool would not find its data.- Windows:
set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION <bin>),set(CMAKE_INSTALL_OPENMP_LIBRARIES TRUE),include(InstallRequiredSystemLibraries)unlessNO_SYSTEM_RUNTIME, ascmake/package_nsis.cmakedoes for the OpenMS installer. - macOS with
SIGNING_IDENTITY: aninstall(CODE)step that runscodesign --force --options runtime --timestamp --sign <identity>over every Mach-O file under<bin>and<lib>of the install prefix. Without the option, signatures are left as they are: copying does not invalidate them, so a locally deployed tree runs; notarization remains the distributor's step. openms_install_runtime()records nothing global and can be called once per consumer project; calling it from the top-levelCMakeLists.txtbeforeinclude(CPack)is the documented use.
Sizes for orientation, from the Linux x86_64 SDK of #10248 (with ONNX): lib/ 203 files, 259 MB; share/OpenMS 81 MB. A deployed tool is therefore about 340 MB unpacked, 120 MB compressed, dominated by libOpenMS's own closure; NO_MODELS and RESOLVE_DEPENDENCIES are the only real levers, and both are small.
3. An SDK marker in the package
The helper has to know whether OPENMS_LIB_DIR is a self-contained runtime directory (SDK) or a bare library directory (cmake --install prefix). package_sdk.sh writes lib/cmake/OpenMS/OpenMSSDK.cmake (Windows: CMake/OpenMSSDK.cmake) into the staged SDK:
set(OpenMS_SDK TRUE)
set(OpenMS_SDK_PLATFORM "Linux-x86_64") # from the archive name
set(OpenMS_SDK_MACOS_MINIMUM "15.0") # macOS only, the value the README states
cmake/OpenMSConfig.cmake.in includes the file when it exists and sets OpenMS_SDK FALSE otherwise, the way it already includes the CLI and GUI target files only when present. Consumers get OpenMS_SDK for their own messages and checks; the helper uses it to choose between copying and resolving.
4. Documentation
cmake/OpenMSSDKReadme.txt: a section "Deploying your program" with the five-line example, the resulting layout (bin/,lib/,share/OpenMS), and the per-platform notes: Linux inherits the SDK's glibc baseline (Ubuntu 24.04), and a.debthat bundles libraries is fine for a vendor package but not for a distribution; Windows needs the MSVC runtime, which the helper installs; macOS needs re-signing and notarization for distribution.doc/openms/docs/manual/develop/link-external-code-to-openms.md: a "Deploying" section with the same content, plusRESOLVE_DEPENDENCIESfor source installations.CHANGELOG.
5. Tests
src/tests/external: the example consumer project gets an install stage withopenms_install_runtime(TARGETS TestExternalCodeCLI TestExternalCodePeptDeep)(the latter forOpenMS_WITH_ONNX), so the example that documents building also documents deploying.src/tests/CMakeLists.txt(OPENMS_TEST_INSTALLED_CONSUMER): three new fixture steps afterTestExternalCode_build, in the pattern of the existing_install/_move/_configure/_build/_runchain and ofTestExternalCodeRelocated_move:TestExternalCode_deploy:cmake --install <consumer build> --prefix <scratch>/deployed.TestExternalCode_deploy_move: rename the installation prefix the consumer was built against, so that the deployed tree cannot reach back to it.TestExternalCode_deploy_run: run<deployed>/bin/TestExternalCodeCLI -greeting ...and, with ONNX,TestExternalCodePeptDeep, under a scrubbed environment (--unsetLD_LIBRARY_PATH,DYLD_LIBRARY_PATH,DYLD_FALLBACK_LIBRARY_PATH,OPENMS_DATA_PATH; on Windows aPATHwithout the installation). Then assert on the tree: no headers, nolib/cmake, no.a/.lib;share/OpenMS/LICENSESholds the third-party texts in a vcpkg build; on Windowsvcruntime*.dllandmsvcp*.dllare present; on macOScodesign --verifypasses on every Mach-O file.
tools/ci/package_sdk.sh: after the consumer build against the extracted SDK, deploy it, delete the extracted SDK, run the deployed tools the same way. This runs inrelease.ymlon all four build jobs and is the check a user of the helper actually relies on: the deployed tree is self-contained.- A CPack smoke test in the same chain:
cpack -G TGZ(ZIPon Windows) in the consumer build, and a listing of the archive that showsbin/,lib/andshare/OpenMS/LICENSES/. Cheap, and it catches a helper that emits install rules CPack does not pick up (component mismatches, missingCPACK_COMPONENTS_ALL).
Implementation plan
Two PRs, the first independent of the second:
PR A: third-party licenses (about half a day)
cmake/install_third_party_licenses.cmake, included fromsrc/openms/CMakeLists.txt.- "Licenses" section in
cmake/OpenMSSDKReadme.txt. - Check in
tools/ci/package_sdk.sh. - CHANGELOG.
PR B: deployment helper, marker, tests, docs (two to three days including the three-platform CI iterations)
cmake/OpenMSRuntimeExcludes.cmake: the exclusion regexes moved out ofcmake/package_general.cmake; that file includes it. No behaviour change for the installers.cmake/OpenMSDeploy.cmakewithopenms_install_runtime(); installed bycmake/export_macros.cmake; included fromcmake/OpenMSConfig.cmake.in.- SDK marker:
package_sdk.shwritesOpenMSSDK.cmake;OpenMSConfig.cmake.inincludes it when present. - Install stage in
src/tests/external/CMakeLists.txt; fixture steps insrc/tests/CMakeLists.txt; deployment step inpackage_sdk.sh. - README, developer manual, CHANGELOG.
Suggested order inside PR B: 1 and 2 first with the Linux consumer test, then macOS (signing) and Windows (system runtime, DLL directory), then the SDK check. The consumer tests run in the ci-base presets on every PR, so the three platforms are covered before release.yml ever runs the SDK path.
Acceptance criteria
-
share/OpenMS/LICENSESin the SDK archives and the installers of a vcpkg build holds one license text per bundled port, andpackage_sdk.shfails when it does not. -
find_package(OpenMS CONFIG)providesopenms_install_runtime()andOpenMS_SDKfrom the SDK and from acmake --installprefix, on Linux, macOS and Windows. - The five-line consumer above, installed with
cmake --install, yields a tree that runs its tool with the SDK removed and a scrubbed environment, and findsshare/OpenMSwithoutOPENMS_DATA_PATH; proven by the installed-consumer tests on every PR and by the SDK check inrelease.yml. - The deployed tree contains no headers, CMake files, static archives or import libraries; on Windows it contains the MSVC runtime; on macOS every Mach-O file passes
codesign --verify, and withSIGNING_IDENTITYcarries that identity. -
cpack -G TGZ/ZIPof the consumer produces an archive withbin/,lib/andshare/OpenMS/LICENSES/. - SDK README and developer manual document deployment; CHANGELOG entries for both PRs.
Open questions
- Default for a non-SDK installation: resolve dependencies automatically (proposed), or require
RESOLVE_DEPENDENCIESexplicitly and otherwise copyOPENMS_LIB_DIReven though it is incomplete? Automatic is the useful default; the option is then only a way to force resolution for an SDK. - Should the license texts also carry a mapping "port to bundled files"? Generating it needs the runtime closure at configure time. Proposed: no; the port names are enough for attribution.
- Should the OpenMS installers get a "Licenses" page or menu entry now that the texts are there? Separate, small, optional.
share/OpenMS/THIRDPARTYandTOOLSare needed by TOPP tools that spawn search engines and by the tool registry; a deployed custom tool needs neither, but excluding them saves little. Proposed: copy everything unlessNO_SHARE.
Related
- #10248: the SDK this builds on; the README there already states the runtime layout and
OPENMS_DATA_PATH. TestExternalCodeRelocated(src/tests/external/relocated): the "move the prefix away" pattern the deployment check reuses.cmake/package_general.cmake,cmake/package_nsis.cmake: the installers' runtime-dependency and system-runtime handling the helper mirrors.- #10230 (Debian package hygiene): unrelated in code, but the same class of "what exactly do we ship" questions.
- Lenguaje dominante
- C++
- Estrellas
- 623
- Forks
- 441
- Merge medio
- 18 h 15 min
- PR fusionados (30 d)
- 255
Preparar el entorno
Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de OpenMS/OpenMS
-
new contributor
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
OpenMS/OpenMS#10512 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
pepXML reader requires the optional 'no_cut' attribute, so OpenMS cannot read back its own pepXML for unknown enzymesPosiblemente ocupada @kg290 la tomó hace 13 días. Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 87/100
OpenMS/OpenMS#10321 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
[FEATUREFINDER] Biosaur2Algorithm::centroidProfileSpectra_: dead drift-time guard would drop every FAIMS CVQuizá libre de nuevo @kavyansh-1 la tomó hace 31 días y no hay ningún pull request abierto. Abiertodefect
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
OpenMS/OpenMS#10005 · 3 comentarios ·
Los mantenedores suelen responder en 1 día
-
Vendor readers (Bruker .d, Thermo .raw): speed, streaming/random access, non-IM Bruker formatsAbierto
Dificultad 5/5 Más de una semana Aptitud para principiantes 20/100
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
Los mantenedores suelen responder en 1 día
Todos los issues de OpenMS/OpenMS
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
-
backend bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
wait.h with wrong descriptionAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
-
Mention parakeet-ffm in READMEAbierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 72/100
mudler/parakeet.cpp#99 ·
Los mantenedores suelen responder en 1 día
-
enhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
raspberrypi/rpi-imager#1773 ·
Los mantenedores suelen responder en 1 día