Skip to main content

Authoring script ports

Script ports, also called helper ports, expose functions for other ports to consume during their build process. For instance, the kmpkg-cmake port defines the kmpkg_cmake_configure() function for other ports to consume. By packaging common scripts into a helper port, maintenance becomes more streamlined as updates can be made in a single location. Additionally, helper ports can be versioned and depended upon using the same mechanisms as regular ports.

How do they work?

Helper ports are implemented via the kmpkg-port-config.cmake extension mechanism.

Before a port is executed, kmpkg will import any kmpkg-port-config.cmake file that has been exported by the direct dependencies of the port about to be executed.

If a helper port depends on a different helper port, it must explicitly import the kmpkg-port-config.cmake file of its dependency. Helper-to-helper port dependencies should not be marked as host dependencies, this ensures that one script can depend upon the other being in the same install directory.

Ports that depend on a helper port should mark the dependency as a host dependency.

Helper ports must always install their kmpkg-port-config.cmake file in a share/${PORT} subdirectory in the installation tree.

Example: Write a simple helper port

1 - Create a CMake file that defines the helper function.

my-helper/my_helper_function.cmake

include_guard(GLOBAL)

function(my_helper_function)
message(STATUS "my_helper_function() was called")
my_other_helper_function()
endfunction()

The include_guard(GLOBAL) at the top of the file protect against redefining this function when the file is included multiple times.

The following lines declare a function named my_helper_function that displays a message and calls the my_other_helper_function that is defined in a different helper port.

2 - Create the helper port's porftile.cmake file

my-helper/portfile.cmake

set(KMPKG_POLICY_CMAKE_HELPER_PORT enabled)

file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/my_helper_function.cmake" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/kmpkg-port-config.cmake" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")

file(INSTALL "${KMPKG_ROOT_DIR}/LICENSE.txt" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright)

By enabling the KMPKG_POLICY_CMAKE_HELPER_PORT policy, kmpkg enables post-build checks that apply specifically to helper ports. Specifically, checks that kmpkg-port-config.cmake is installed in the correct path and that no files are installed in the include directory.

The next lines install the required kmpkg-port-config.cmake and copyright files in their correct location (share/${PORT}).

3 - Create the helper port's kmpkg.json file

my-helper/kmpkg.json

{
"name": "my-helper",
"version-date": "2024-03-20",
"description": "Provide my_helper_function()",
"license": "MIT",
"dependencies": [
{ "name": "my-other-helper" }
]
}

We recommend using version-date as the versioning scheme for helper ports.

The dependencies in this example contain a reference to another helper port named my-other-helper. The dependency is purposefuly not marked as a host dependency since this is a helper-to-helper port dependency.

4 - Create the helper port's kmpkg-port-config.cmakefile

my-helper/kmpkg-port-config.cmake

include_guard(GLOBAL)

include("${CMAKE_CURRENT_LIST_DIR}/../my-other-helper/kmpkg-port-config.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/my_helper_function.cmake")

The kmpkg-port-config.cmake file consists of three lines, the first is a global include guard that prevents the file from being included multiple times.

The second line includes my-other-helper/kmpkg-port-config.cmake to make the functions in my-other-helper available to ports that depend on my-helper without them having to include my-other-helper in their list of direct dependencies.

Finally, the my_helper_function.cmake file which contains the my_helper_function definition is included.

5 - Consume my-helper in a manifest

Any consumer of my-helper only needs to include a direct dependency to my-helper itself, no dependency to my-other-helper is needed. The consuming manifest should mark the dependency as a host dependency.

my-port/kmpkg.json

{
"name": "my-port",
"version": "1.0.0",
"dependencies": [
{
"name": "my-helper",
"host": true
}
]
}

This makes my_helper_function available in my-port/portfile.cmake.

my-port/portfile.cmake

my_helper_function()