| The information on this page refers to v5.1 and newer, which added support for macOS on ARM. |
The current LM-X SDK and End-user Tools installers build and install native ARM64 binaries for Apple silicon Macs. The signing workflow is described below.
The procedures described in this page apply to the macOS installers supplied with LM-X v5.1 and newer.
Vendor signing requirement
Important
Before distributing LM-X End-user Tools (EUT) for macOS, the software vendor must sign all Mach-O executables and dynamic libraries in the final EUT installation with the vendor's own Developer ID Application certificate.
The EUT runtime includes the X-Formation executables, the vendor-specific liblmxvendor.dylib file, and supporting libraries. At a minimum, sign the following files when they are present:
- lmx-serv
- lmxendutil
- liblmxvendor.dylib
- libssl.4.dylib
- libcrypto.4.dylib
In addition to signing these files, sign any other Mach-O executable or dynamic library included in the package.
Ensure that every binary uses the same Apple Team ID
The lmx-serv file uses the Hardened Runtime, which enables macOS library validation. Library validation permits the process to load non-Apple libraries only when they are signed with the same Apple Team ID as the executable.
The LM-X executables and bundled libraries may initially be signed by X-Formation. A vendor library signed by another Apple Team ID cannot be loaded into an X-Formation-signed lmx-serv. Re-signing only lmx-serv and lmxendutil is also insufficient: the vendor and OpenSSL libraries would still have a different Team ID.
If the signatures do not match, macOS may reject a library with an error similar to:
Library not loaded: @rpath/liblmxvendor.dylib
mapping process and mapped file (non-platform) have different Team IDs
Signing the complete EUT runtime with one Developer ID establishes a consistent Team ID and allows the hardened lmx-serv process to load its dependencies. Do not disable library validation as a substitute for signing the runtime correctly.
For further information on using Apple Team IDs, see Apple's library validation documentation.
Prerequisites
Before signing:
If you haven't already, join the Apple Developer Program and obtain a Developer ID Application certificate.
Install the certificate and its private key in a keychain available to the account running the installer.
Confirm that the signing identity is available:
security find-identity -v -p codesigning
Use the complete identity shown by that command, for example:
Developer ID Application: Example Company (TEAMID1234)
When installing over SSH or from CI, unlock the keychain that contains the certificate before running the installer, as shown below.
security unlock-keychain /path/to/signing.keychain-db
Signing through the SDK installer
The SDK installer can use one Developer ID identity for both parts of the installation, as follows.
- The SDK installer records the identity in the installed macOS SDK configuration and uses it for binaries and libraries built during SDK compilation.
- If EUT installation is selected, it passes the same identity to the bundled EUT installer.
- The EUT installer copies the complete runtime into its final location.
- The SDK installer signs dynamic libraries first, followed by the executables, and verifies every resulting signature.
- If license server startup is requested, the license server is started only after signing has succeeded.
Interactive SDK installation
To use interactive SDK installation, run the SDK installer normally. On macOS, the installer will ask whether you want to provide a Developer ID Application certificate. Answer Y to this prompt, and enter the complete identity, as shown in the following example.
Do you want to provide your Developer ID Certificate [Y/N]: Y
Developer ID Certificate: Developer ID Application: Example Company (TEAMID1234)
If you subsequently choose to install the End-user Tools, the SDK installer forwards your specified identity automatically. The nested EUT installer does not ask for it again.
Silent SDK installation
Supply the -d option (used exclusively for macOS) after the installer's "--" separator, as shown in the following example.
./lmx-sdk_v6.2.1_macos_arm64.sh -- \ -e accept \ -i "/path/to/lmx-sdk-6.2.1" \ -b \ -f "/path/to/lmx.lic" \ -t \ -d "Developer ID Application: Example Company (TEAMID1234)"
The -t option installs EUT after SDK compilation. The SDK installer forwards the identity to EUT, which signs the installed EUT runtime.
If no Developer ID is provided, SDK build outputs may receive ad-hoc signatures. Ad-hoc signing is useful for local development, but it is not a replacement for Developer ID signing and notarization of software distributed to customers.
Signing through the standalone EUT installer
The standalone EUT installer accepts the -d option and signs every Mach-O file after all files, including the selected vendor library, have been copied to the final installation directory.
Libraries are signed before executables. Each signature is then checked with codesign --verify --strict. The installation fails if signing or verification fails.
Interactive EUT installation
The current standalone EUT installer does not prompt for a signing identity. To sign an otherwise interactive installation, provide only the -d option on the command line and answer the remaining installer prompts normally:
./lmx-enduser-tools_v6.2.1_macos_arm64.sh -- \ -d "Developer ID Application: Example Company (TEAMID1234)"
Silent EUT installation
For an unattended installation, supply all required choices together with the -d option, as shown in the following example.
./lmx-enduser-tools_v6.2.1_macos_arm64.sh -- \ -e accept \ -i "/path/to/lmx-6.2.1" \ -l "/path/to/liblmxvendor.dylib" \ -d "Developer ID Application: Example Company (TEAMID1234)"
The -d option is optional to allow local or development installations to remain unsigned. The -d option should be supplied when preparing an EUT installation for redistribution.
Manual signing
If you do not use installer-managed signing, sign the files after assembling the final EUT runtime. Sign nested code such as dynamic libraries first and the executables last, as shown in the following example.
identity="Developer ID Application: Example Company (TEAMID1234)"
eut_dir="/path/to/lmx-6.2.1"
for file in \
"${eut_dir}/liblmxvendor.dylib" \
"${eut_dir}/libssl.4.dylib" \
"${eut_dir}/libcrypto.4.dylib"
do
codesign --force --sign "${identity}" --timestamp --options runtime "${file}"
done
for file in \
"${eut_dir}/lmx-serv" \
"${eut_dir}/lmxendutil"
do
codesign --force --sign "${identity}" --timestamp --options runtime "${file}"
done
If your package contains other Mach-O files, sign them too. You can identify Mach-O files with the file command:
find "${eut_dir}" -type f -exec file {} \; | grep 'Mach-O'
Verifying the installed runtime
Verify every signed file explicitly, as shown in the following example.
for file in \
"${eut_dir}/liblmxvendor.dylib" \
"${eut_dir}/libssl.4.dylib" \
"${eut_dir}/libcrypto.4.dylib" \
"${eut_dir}/lmx-serv" \
"${eut_dir}/lmxendutil"
do
codesign --verify --strict --verbose=2 "${file}"
codesign --display --verbose=4 "${file}" 2>&1 | grep -E 'Authority=|TeamIdentifier='
done
Confirm that:
- Verification succeeds for every file
- Every file reports the vendor's expected
TeamIdentifier - The signatures include a secure timestamp and Hardened Runtime where applicable
- lmx-serv starts and loads liblmxvendor.dylib successfully on Apple silicon
If a process exits with a "Killed: 9" message, a library fails to load, or Team IDs differ, inspect the signatures again before investigating the license configuration.
Notarizing the distribution
You may (and, for software distributed outside the Mac App Store, generally should) notarize the final package under your own Apple Team ID, as follows.
- Assemble the final EUT runtime, including the vendor library and all dependencies.
- Sign every Mach-O file with your Developer ID Application certificate.
- Verify every signature and Team ID.
- Create the final supported distribution container, such as a ZIP archive, DMG, or signed PKG.
- Submit the file with
xcrun notarytoolunder your Apple Team ID. - Check the notarization log, staple the ticket where the package format supports stapling, and test the final download with Gatekeeper enabled.
Notarization does not replace code signing and does not correct mixed Team IDs; it only validates the package that you have already signed. See Apple's notarization documentation for the current requirements and commands.