From b95c7be91d70f45e6ab9922af96e0a9d7671047a Mon Sep 17 00:00:00 2001 From: Dario Gabriel Lipicar Date: Sat, 7 Mar 2026 11:50:55 +0000 Subject: [PATCH 1/2] fixed package generation, remove unneded library load workarounds --- tutorial-wrapping-c-library.md | 89 ++++++++-------------------------- 1 file changed, 21 insertions(+), 68 deletions(-) diff --git a/tutorial-wrapping-c-library.md b/tutorial-wrapping-c-library.md index 6ae0603..bb3eebf 100644 --- a/tutorial-wrapping-c-library.md +++ b/tutorial-wrapping-c-library.md @@ -637,53 +637,28 @@ nix build 'github:logos-co/logos-liblogos' --out-link ./logos ### 5.2 Set up the modules directory -`logoscore` expects modules in subdirectories, each with a `manifest.json`: +`logoscore` expects modules in subdirectories, each with a `manifest.json`. Rather than copying files and writing the manifest manually, use the Nix bundler to create an LGX package and install it with the package manager: ```bash -mkdir -p modules/calc_module +# Bundle the module into an LGX package +nix bundle --bundler 'github:logos-co/nix-bundle-lgx' '.#lib' -o lgx-result -# Linux -cp result/lib/calc_module_plugin.so modules/calc_module/ -cp result/lib/libcalc.so modules/calc_module/ - -# macOS -# cp result/lib/calc_module_plugin.dylib modules/calc_module/ -# cp result/lib/libcalc.dylib modules/calc_module/ +# Install it into a modules directory using the Logos Package Manager +nix build 'github:logos-co/logos-package-manager-module#cli' --out-link ./pm +mkdir -p modules +./pm/bin/lgpm --modules-dir ./modules install --file lgx-result/*.lgx ``` -Create `modules/calc_module/manifest.json`: +This extracts the plugin, external libraries, and manifest into the correct directory structure: -```json -{ - "name": "calc_module", - "version": "1.0.0", - "description": "Calculator module wrapping libcalc C library", - "type": "core", - "main": { - "linux-aarch64": "calc_module_plugin.so", - "linux-x86_64": "calc_module_plugin.so", - "darwin-arm64": "calc_module_plugin.dylib", - "darwin-x86_64": "calc_module_plugin.dylib" - }, - "dependencies": [] -} +``` +modules/calc_module/ +├── calc_module_plugin.dylib # (or .so on Linux) +├── libcalc.dylib # (or .so on Linux) +└── manifest.json # Auto-generated ``` -The `main` object maps platform variant names to the plugin filename. `logoscore` uses this to find the right binary for your OS and architecture. - -### 5.3 Set library path (macOS workaround) - -On macOS, RPATH may not be correctly set in the built plugin (this is a known logos-module-builder issue). If `logoscore` fails to load the module with a "library not found" error, set the library path manually: - -```bash -# macOS only — needed until RPATH is fixed in logos-module-builder -export DYLD_LIBRARY_PATH=result/lib/ - -# Linux equivalent (usually not needed if RPATH is set correctly) -# export LD_LIBRARY_PATH=result/lib/ -``` - -### 5.4 Call methods +### 5.3 Call methods ```bash # Call add(3, 5) @@ -739,39 +714,23 @@ Method call successful. Result: ... ## Step 6: Package for Distribution (Optional) -### 6.1 Build the `lgx` tool +The LGX package created in Step 5.2 is a **local** package — its libraries still reference `/nix/store` paths, so it only works on the machine that built it. To create a **portable** package that can be distributed to other machines, use the `#portable` bundler: ```bash -nix build 'github:logos-co/logos-package#lgx' --out-link ./lgx +nix bundle --bundler 'github:logos-co/nix-bundle-lgx#portable' '.#lib' ``` -### 6.2 Create a package +Portable LGX packages are fully self-contained with no `/nix/store` references at runtime. These are the packages used by the Logos App Package Manager UI and published to [logos-modules](https://github.com/logos-co/logos-modules) releases. -```bash -# Create an empty LGX package -./lgx/bin/lgx create calc_module --name calc_module - -# Add the Linux variant -./lgx/bin/lgx add calc_module.lgx \ - --variant linux-aarch64 \ - --files result/lib/ --main calc_module_plugin.so - -# Or on Mac, to add the Mac variant -./lgx/bin/lgx add calc_module.lgx \ - --variant darwin-arm64 \ - --files result/lib/ --main calc_module_plugin.dylib - -# Verify the package -./lgx/bin/lgx verify calc_module.lgx -``` - -On another machine, install with the Logos Package Manager: +To install a portable package on another machine: ```bash nix build 'github:logos-co/logos-package-manager-module#cli' --out-link ./pm ./pm/bin/lgpm --modules-dir ./modules install --file calc_module.lgx ``` +> **Note:** Local builds of `logoscore` / `logos-app` (via `nix build`) expect **local** `.lgx` packages. Portable builds (via `nix build '.#bin-bundle-dir'`, `.#bin-appimage`, or `.#bin-macos-app`) expect **portable** `.lgx` packages. See the [logos-app README](https://github.com/logos-co/logos-app/blob/master/README.md) for details. + --- ## Common Wrapping Patterns @@ -982,13 +941,7 @@ Q_INVOKABLE void initLogos(LogosAPI* api); // No override! Cannot load library calc_module_plugin.so: libcalc.so: cannot open shared object file ``` -**Fix:** Ensure `libcalc.so` / `libcalc.dylib` is in the same directory as the plugin. The build system should set RPATH to `$ORIGIN` (Linux) / `@loader_path` (macOS) so the plugin looks for libraries in its own directory. - -**macOS note:** As of writing, the RPATH may not be correctly set by logos-module-builder on macOS. As a workaround, set the library path before running: - -```bash -export DYLD_LIBRARY_PATH=result/lib/ -``` +**Fix:** Ensure `libcalc.so` / `libcalc.dylib` is in the same directory as the plugin. The build system sets RPATH to `$ORIGIN` (Linux) / `@loader_path` (macOS) so the plugin looks for libraries in its own directory. ### `initLogos` stores API pointer in wrong variable From 4e9081bbd8a6d0cf82c6eb44aa05e490a621f39d Mon Sep 17 00:00:00 2001 From: Dario Gabriel Lipicar Date: Sat, 7 Mar 2026 12:20:39 +0000 Subject: [PATCH 2/2] Update logos-calc-module example files --- logos-calc-module/CMakeLists.txt | 2 +- logos-calc-module/flake.lock | 406 ------------------- logos-calc-module/lib/libcalc.h | 7 - logos-calc-module/lib/libcalc.so | Bin 69512 -> 0 bytes logos-calc-module/module.yaml | 1 + logos-calc-module/src/calc_module_plugin.cpp | 3 +- logos-calc-module/src/calc_module_plugin.h | 7 +- 7 files changed, 8 insertions(+), 418 deletions(-) delete mode 100644 logos-calc-module/flake.lock delete mode 100755 logos-calc-module/lib/libcalc.so diff --git a/logos-calc-module/CMakeLists.txt b/logos-calc-module/CMakeLists.txt index e796327..1a7469d 100644 --- a/logos-calc-module/CMakeLists.txt +++ b/logos-calc-module/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.14) project(CalcModulePlugin LANGUAGES CXX) -# Include the Logos Module CMake helper +# Include the Logos Module CMake helper (provided by logos-module-builder) if(DEFINED ENV{LOGOS_MODULE_BUILDER_ROOT}) include($ENV{LOGOS_MODULE_BUILDER_ROOT}/cmake/LogosModule.cmake) elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/LogosModule.cmake") diff --git a/logos-calc-module/flake.lock b/logos-calc-module/flake.lock deleted file mode 100644 index f46d117..0000000 --- a/logos-calc-module/flake.lock +++ /dev/null @@ -1,406 +0,0 @@ -{ - "nodes": { - "logos-capability-module": { - "inputs": { - "logos-cpp-sdk": "logos-cpp-sdk_2", - "logos-liblogos": "logos-liblogos_2", - "nixpkgs": [ - "logos-module-builder", - "logos-liblogos", - "logos-capability-module", - "logos-liblogos", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1767809111, - "narHash": "sha256-jehjsB+BpDJlVu3I7x+vFVOdXmy9MDmFTJtRqzFUONo=", - "owner": "logos-co", - "repo": "logos-capability-module", - "rev": "7b35383e0aa4e28a4633ed18a87efb57636939b1", - "type": "github" - }, - "original": { - "owner": "logos-co", - "repo": "logos-capability-module", - "type": "github" - } - }, - "logos-cpp-sdk": { - "inputs": { - "nixpkgs": "nixpkgs" - }, - "locked": { - "lastModified": 1772028960, - "narHash": "sha256-BDWFjaKeoJW8oWDlPphNINt5U3P1xt1z1Y4f9jyC7uU=", - "owner": "logos-co", - "repo": "logos-cpp-sdk", - "rev": "95f763b48d74bcdc63093b05159f43500cab139e", - "type": "github" - }, - "original": { - "owner": "logos-co", - "repo": "logos-cpp-sdk", - "type": "github" - } - }, - "logos-cpp-sdk_2": { - "inputs": { - "nixpkgs": "nixpkgs_2" - }, - "locked": { - "lastModified": 1761230734, - "narHash": "sha256-CMRUwXH7pJZ1OI6bd/TDDDXKqQ1tQZHQEOOwK8TgYHI=", - "owner": "logos-co", - "repo": "logos-cpp-sdk", - "rev": "4b143922c190df00bb3835441c9f0075cb28283b", - "type": "github" - }, - "original": { - "owner": "logos-co", - "repo": "logos-cpp-sdk", - "type": "github" - } - }, - "logos-cpp-sdk_3": { - "inputs": { - "nixpkgs": "nixpkgs_3" - }, - "locked": { - "lastModified": 1761230734, - "narHash": "sha256-CMRUwXH7pJZ1OI6bd/TDDDXKqQ1tQZHQEOOwK8TgYHI=", - "owner": "logos-co", - "repo": "logos-cpp-sdk", - "rev": "4b143922c190df00bb3835441c9f0075cb28283b", - "type": "github" - }, - "original": { - "owner": "logos-co", - "repo": "logos-cpp-sdk", - "type": "github" - } - }, - "logos-cpp-sdk_4": { - "inputs": { - "nixpkgs": "nixpkgs_4" - }, - "locked": { - "lastModified": 1772028960, - "narHash": "sha256-BDWFjaKeoJW8oWDlPphNINt5U3P1xt1z1Y4f9jyC7uU=", - "owner": "logos-co", - "repo": "logos-cpp-sdk", - "rev": "95f763b48d74bcdc63093b05159f43500cab139e", - "type": "github" - }, - "original": { - "owner": "logos-co", - "repo": "logos-cpp-sdk", - "type": "github" - } - }, - "logos-cpp-sdk_5": { - "inputs": { - "nixpkgs": "nixpkgs_5" - }, - "locked": { - "lastModified": 1767724329, - "narHash": "sha256-UPkqxqxbKwU5Dmu00TnjiJVXUmfVylF3p1qziEuYwIE=", - "owner": "logos-co", - "repo": "logos-cpp-sdk", - "rev": "32f1d7080d784ff044d91d076ef2f0c7305d4784", - "type": "github" - }, - "original": { - "owner": "logos-co", - "repo": "logos-cpp-sdk", - "type": "github" - } - }, - "logos-liblogos": { - "inputs": { - "logos-capability-module": "logos-capability-module", - "logos-cpp-sdk": "logos-cpp-sdk_4", - "logos-module": "logos-module", - "nix-bundle-appimage": "nix-bundle-appimage", - "nix-bundle-dir": "nix-bundle-dir_2", - "nixpkgs": [ - "logos-module-builder", - "logos-liblogos", - "logos-cpp-sdk", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1772115748, - "narHash": "sha256-sPdAuYiLOjsulrk+uKMT7EG05ZlGT7OYEpgUh+f0nME=", - "owner": "logos-co", - "repo": "logos-liblogos", - "rev": "07780444deb99f10e600247e3696ba495f2f071a", - "type": "github" - }, - "original": { - "owner": "logos-co", - "repo": "logos-liblogos", - "type": "github" - } - }, - "logos-liblogos_2": { - "inputs": { - "logos-cpp-sdk": "logos-cpp-sdk_3", - "nixpkgs": [ - "logos-module-builder", - "logos-liblogos", - "logos-capability-module", - "logos-liblogos", - "logos-cpp-sdk", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1761845775, - "narHash": "sha256-ulK8xq05ejK6qIgZ7WtWb/MJt2rk5BKfDA2z7mM3wq8=", - "owner": "logos-co", - "repo": "logos-liblogos", - "rev": "a92c2c1268bc70764c8f73c7bce07d21024f5af9", - "type": "github" - }, - "original": { - "owner": "logos-co", - "repo": "logos-liblogos", - "type": "github" - } - }, - "logos-module": { - "inputs": { - "logos-cpp-sdk": "logos-cpp-sdk_5", - "nixpkgs": [ - "logos-module-builder", - "logos-liblogos", - "logos-module", - "logos-cpp-sdk", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1770999556, - "narHash": "sha256-anpsEniGTTwUAwknRxjaT9GP4avHzIsolEHdHDTV9rM=", - "owner": "logos-co", - "repo": "logos-module", - "rev": "d1b35f335f938bb5de21a2a6010f1104075bdb1c", - "type": "github" - }, - "original": { - "owner": "logos-co", - "repo": "logos-module", - "type": "github" - } - }, - "logos-module-builder": { - "inputs": { - "logos-cpp-sdk": "logos-cpp-sdk", - "logos-liblogos": "logos-liblogos", - "nixpkgs": [ - "logos-module-builder", - "logos-cpp-sdk", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1770934129, - "narHash": "sha256-RjeB17MQh4HcS5vKtSrDM/J7fz3K8ZDNpswCGr5JF/k=", - "owner": "logos-co", - "repo": "logos-module-builder", - "rev": "a86eea50450511f4474b35032e5fd218a0f17c3c", - "type": "github" - }, - "original": { - "owner": "logos-co", - "repo": "logos-module-builder", - "type": "github" - } - }, - "nix-bundle-appimage": { - "inputs": { - "nix-bundle-dir": "nix-bundle-dir", - "nixpkgs": "nixpkgs_6" - }, - "locked": { - "lastModified": 1772047346, - "narHash": "sha256-RUsTUxKCxuQ3+D2LfBbK0EX1vF7HNMkpWgOGFfZbrEg=", - "owner": "logos-co", - "repo": "nix-bundle-appimage", - "rev": "4d68437c97ac59c3c70c1b2b116235c434d571a8", - "type": "github" - }, - "original": { - "owner": "logos-co", - "repo": "nix-bundle-appimage", - "type": "github" - } - }, - "nix-bundle-dir": { - "inputs": { - "nixpkgs": [ - "logos-module-builder", - "logos-liblogos", - "nix-bundle-appimage", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1771971384, - "narHash": "sha256-fq0H+sxQhkGN054jdN+ZfHZibbOjHA+KD5SpRH78T1g=", - "owner": "logos-co", - "repo": "nix-bundle-dir", - "rev": "1ecb9662145a1ad84007a970b4bef50a4af159c9", - "type": "github" - }, - "original": { - "owner": "logos-co", - "repo": "nix-bundle-dir", - "type": "github" - } - }, - "nix-bundle-dir_2": { - "inputs": { - "nixpkgs": "nixpkgs_7" - }, - "locked": { - "lastModified": 1771971384, - "narHash": "sha256-fq0H+sxQhkGN054jdN+ZfHZibbOjHA+KD5SpRH78T1g=", - "owner": "logos-co", - "repo": "nix-bundle-dir", - "rev": "1ecb9662145a1ad84007a970b4bef50a4af159c9", - "type": "github" - }, - "original": { - "owner": "logos-co", - "repo": "nix-bundle-dir", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1759036355, - "narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1759036355, - "narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_3": { - "locked": { - "lastModified": 1759036355, - "narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_4": { - "locked": { - "lastModified": 1759036355, - "narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_5": { - "locked": { - "lastModified": 1759036355, - "narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_6": { - "locked": { - "lastModified": 1771848320, - "narHash": "sha256-0MAd+0mun3K/Ns8JATeHT1sX28faLII5hVLq0L3BdZU=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "2fc6539b481e1d2569f25f8799236694180c0993", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_7": { - "locked": { - "lastModified": 1770562336, - "narHash": "sha256-ub1gpAONMFsT/GU2hV6ZWJjur8rJ6kKxdm9IlCT0j84=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "d6c71932130818840fc8fe9509cf50be8c64634f", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "logos-module-builder": "logos-module-builder", - "nixpkgs": [ - "logos-module-builder", - "nixpkgs" - ] - } - } - }, - "root": "root", - "version": 7 -} diff --git a/logos-calc-module/lib/libcalc.h b/logos-calc-module/lib/libcalc.h index 8365297..b38246e 100644 --- a/logos-calc-module/lib/libcalc.h +++ b/logos-calc-module/lib/libcalc.h @@ -1,10 +1,3 @@ -/** - * libcalc - A tiny calculator C library - * - * This is a minimal C library used to demonstrate - * wrapping a C library as a Logos module. - */ - #ifndef LIBCALC_H #define LIBCALC_H diff --git a/logos-calc-module/lib/libcalc.so b/logos-calc-module/lib/libcalc.so deleted file mode 100755 index 801d0186cf7eefbe58cfb9af0e2e6844cfd779c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69512 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