Managing dependencies
Met.3D is primarily used with two different package managers. On Linux the first choice is mamba (or conda), which can be used to install third-party dependencies. Additionally, vcpkg is also supported, which can be integrated into cmake. It builds all dependencies from source.
Adding new dependencies
If you require a new dependency for Met.3D, your first step should be to see, whether the package is available via conda-forge for Linux. If it is not, you might consider an alternative that is, or provide documentation on how to use it in our installation instructions.
Additionally, you should check the vcpkg package registry and see, whether it is available for Linux and Windows.
This is usually shown on the right under supported.
If it is supported for all platforms except a few, only the exceptions will be listed.
For example, the qtbase package is available for all platforms except uwp, so its supported list will show !uwp.
Adding a conda dependency
When adding a conda dependency to Met.3D you will need to reference it in several placed.
Our conda package recipe: Add the dependency to
util/conda/Recipe/meta.yamlin the Met.3D repository. If the dependency is a header only library, add it to thehostsection. If it is also required at runtime, add it to therunsection instead.Documentation: Add it to the installation instructions to build Met.3D from source on Linux.
To use your newly added dependency, add the appropriate find_package command to the CMakeLists.txt and link the imported target.
Adding a vcpkg dependency
If you use a new dependency available via vcpkg, you just have to add it to the vcpkg.json file in our git repository.
As with conda, you have to add the appropriate find_package command to the CMakeLists.txt and link the imported target.
Adding a non-existent vcpkg dependency
If your package is not available via vcpkg, you can add a package definition yourself.
This is called an overlay port.
We have a directory in our Met.3D repository, called vcpkg-overlays, that contains all third-party packages not available via vcpkg.
An overlay port is essentially just a cmake script that instructs vcpkg on how to build the package.
You will need a vcpkg.json and a portfile.cmake.
Optionally you can add a usage file containing information on how to find and use the library with cmake.
Inside the vcpkg.json you specify the name of the port, the version, license and dependencies.
The vcpkg.json for glfx looks like this, for example:
1{
2 "name": "glfx",
3 "version": "1.0",
4 "description": "Specialised fork of GLFX for use with Met.3D.",
5 "license": "BSD-2-Clause",
6 "dependencies": [
7 {
8 "name" : "vcpkg-cmake",
9 "host" : true
10 },
11 {
12 "name" : "vcpkg-cmake-config",
13 "host" : true
14 },
15 {
16 "name": "qtbase",
17 "default-features": false,
18 "features": ["opengl"]
19 }
20 ]
21}
It requires the vcpkg-cmake and vcpkg-cmake-config cmake helper packages to build the package,
which is why the host property is set to true.
It also requires qtbase at build and runtime, but only the opengl feature.
The license field has to be a SPDX license identifier.
The portfile.cmake contains the build instructions.
It looks like this:
1vcpkg_from_github(
2 OUT_SOURCE_PATH SOURCE_PATH
3 REPO thorwin-vogt/glfx
4 REF c575b65773625c8800ff562fbd3a5d2615a1c18d
5 SHA512 286c1aae3e6a6d8d617aaeef68d42e57c038fcdf6ca627c5d4c60be4e3639efd9548e07c2696b7b36c48eb398dbb174d8bbc82ff6427f02aca2341289ec8a922
6 HEAD_REF qt6
7)
8
9vcpkg_cmake_configure(SOURCE_PATH ${SOURCE_PATH})
10vcpkg_cmake_install()
11vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/glfx)
12vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/COPYING")
13
14# Install usage file
15file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
It should be fairly explanatory.
We first pull the package from GitHub.
When you first define your package, you can leave the SHA512 field as 0.
Executing cmake will end with an error, that will contain the correct SHA512.
You can now replace the 0 with the correct SHA512.
Next we configure cmake for the sources.
The command vcpkg_cmake_install will build and install the library.
The next line fixes some issues with glfxConfig.cmake, which is used to later find it with cmake.
Not all libraries generate such a file, in which case you won’t need that line, but probably need to write a find script for your library for Met.3D.
vcpkg_install_copyright installs the copyright notice.
The last line installs the usage file.
The usage file for this port looks like this:
1glfx provides CMake targets:
2
3 find_package(glfx CONFIG REQUIRED)
4 target_link_libraries(main PRIVATE glfx::glfx)
Writing a cmake find script
If your dependency does not provide a *Config.cmake file, you have to write a find script for it.
To do this, add a new file to the cmake directory and add a FindLibrary.cmake file.
Replace the “Library” with your library name.
A minimal example could be:
1# Set the name of the package
2set (PKG_NAME YourLibrary)
3
4# Find the include directory
5find_path(${PKG_NAME}_INCLUDE_DIR
6 NAMES # Name of all header files
7 YourLibrary.h
8 PATH_SUFFIXES # Subfolders in the install directory
9 include
10 )
11
12# Find the release library
13find_library(${PKG_NAME}_LIBRARY_RELEASE
14 NAMES
15 YourLibrary
16 PATH_SUFFIXES
17 lib64
18 lib
19 )
20
21# Find the debug library, often suffixed d.
22find_library(${PKG_NAME}_LIBRARY_DEBUG
23 NAMES
24 YourLibraryd
25 PATH_SUFFIXES
26 lib64
27 lib
28 )
29
30# Print what libraries were not found.
31if (NOT ${PKG_NAME}_LIBRARY_DEBUG)
32 message("Debug library for ${PKG_NAME} was not found")
33 set(${PKG_NAME}_LIBRARY_DEBUG "${${PKG_NAME}_LIBRARY_RELEASE}")
34endif()
35
36if (NOT ${PKG_NAME}_LIBRARY_RELEASE)
37 message("Release library for ${PKG_NAME} was not found")
38 set(${PKG_NAME}_LIBRARY_RELEASE "${${PKG_NAME}_LIBRARY_DEBUG}")
39endif()
40
41# handle the QUIETLY and REQUIRED arguments and set ${PKG_NAME}_FOUND to TRUE if
42# all listed variables are TRUE
43find_package_handle_standard_args(${PKG_NAME} REQUIRED_VARS ${PKG_NAME}_LIBRARIES ${PKG_NAME}_INCLUDE_DIR)
44# Marks cmake cached variables as advanced
45mark_as_advanced(${PKG_NAME}_INCLUDE_DIR ${PKG_NAME}_LIBRARIES)
46
47
48# Create imported targets
49# Look for dlls to create shared targets for windows
50if (WIN32)
51 # Set release dll path
52 if (${PKG_NAME}_LIBRARY_RELEASE)
53 string(REPLACE ".lib" ".dll" ${PKG_NAME}_DLL_PATH "${${PKG_NAME}_LIBRARY_RELEASE}")
54 cmake_path(GET ${PKG_NAME}_DLL_PATH FILENAME ${PKG_NAME}_DLL_NAME)
55
56 find_file(${PKG_NAME}_DLL REQUIRED
57 NAMES ${${PKG_NAME}_DLL_NAME}
58 HINTS /bin $ENV{${PKG_NAME}_DIR}/bin
59 PATH_SUFFIXES Release Debug)
60
61 unset(${PKG_NAME}_DLL_PATH)
62 unset(${PKG_NAME}_DLL_NAME)
63 endif()
64
65 # Set debug dll path
66 if (${PKG_NAME}_LIBRARY_DEBUG)
67 string(REPLACE ".lib" ".dll" ${PKG_NAME}_DLL_PATH_DEBUG "${${PKG_NAME}_LIBRARY_DEBUG}")
68 cmake_path(GET ${PKG_NAME}_DLL_PATH_DEBUG FILENAME ${PKG_NAME}_DLL_NAME_DEBUG)
69
70 find_file(${PKG_NAME}_DLL_DEBUG
71 NAMES ${${PKG_NAME}_DLL_NAME_DEBUG}
72 HINTS /bin $ENV{${PKG_NAME}_DIR}/bin
73 PATH_SUFFIXES Release Debug)
74
75 unset(${PKG_NAME}_DLL_PATH_DEBUG)
76 unset(${PKG_NAME}_DLL_NAME_DEBUG)
77 endif()
78
79 # Create imported targets for YourLibrary.
80 if (${PKG_NAME}_FOUND)
81 if (EXISTS "${${PKG_NAME}_DLL}")
82 add_library(yourlibrary::yourlibrary SHARED IMPORTED)
83
84 set_target_properties(yourlibrary::yourlibrary PROPERTIES
85 IMPORTED_LOCATION_RELEASE "${${PKG_NAME}_DLL}"
86 IMPORTED_IMPLIB "${${PKG_NAME}_LIBRARY_RELEASE}"
87 INTERFACE_INCLUDE_DIRECTORIES "${${PKG_NAME}_INCLUDE_DIR}"
88 IMPORTED_CONFIGURATIONS Release)
89
90 if (EXISTS "${${PKG_NAME}_DLL_DEBUG}")
91 set_property(TARGET yourlibrary::yourlibrary APPEND PROPERTY IMPORTED_CONFIGURATIONS Debug)
92 set_target_properties(yourlibrary::yourlibrary PROPERTIES
93 IMPORTED_LOCATION_DEBUG "${${PKG_NAME}_DLL_DEBUG}"
94 IMPORTED_IMPLIB_DEBUG "${${PKG_NAME}_LIBRARY_DEBUG}")
95 endif()
96 else ()
97 add_library(yourlibrary::yourlibrary UNKNOWN IMPORTED)
98 set_target_properties(yourlibrary::yourlibrary PROPERTIES
99 IMPORTED_LOCATION "${${PKG_NAME}_LIBRARY_RELEASE}"
100 INTERFACE_INCLUDE_DIRECTORIES "${${PKG_NAME}_INCLUDE_DIR}")
101
102 if (EXISTS "${${PKG_NAME}_LIBRARY_DEBUG}")
103 set_property(TARGET yourlibrary::yourlibrary APPEND PROPERTY IMPORTED_CONFIGURATIONS Debug)
104 set_target_properties(yourlibrary::yourlibrary PROPERTIES
105 IMPORTED_LOCATION_DEBUG "${${PKG_NAME}_LIBRARY_DEBUG}")
106 endif()
107 endif()
108 endif()
109else()
110 # Create imported targets for YourLibrary.
111 if (${PKG_NAME}_FOUND)
112 add_library(yourlibrary::yourlibrary UNKNOWN IMPORTED)
113
114 set_target_properties(yourlibrary::yourlibrary PROPERTIES
115 IMPORTED_LOCATION_RELEASE "${${PKG_NAME}_LIBRARY_RELEASE}"
116 INTERFACE_INCLUDE_DIRECTORIES "${${PKG_NAME}_INCLUDE_DIR}"
117 IMPORTED_CONFIGURATIONS Release)
118
119 if (EXISTS "${${PKG_NAME}_DLL_DEBUG}")
120 set_property(TARGET yourlibrary::yourlibrary APPEND PROPERTY IMPORTED_CONFIGURATIONS Debug)
121 set_target_properties(yourlibrary::yourlibrary PROPERTIES
122 IMPORTED_LOCATION_DEBUG "${${PKG_NAME}_LIBRARY_DEBUG}")
123 endif()
124 endif()
125endif()
This find script will create imported targets named yourlibrary::yourlibrary.
You can then link to that library via target_link_libraries(Met3D PUBLIC yourlibrary::yourlibrary).
This will also add its include directory to Met.3D’s include path.