---
url: /guide/package-management/distribute-private-libraries.md
---

# Distribute Private Libraries {#distribute-private-libraries}

Xmake supports not only installing packages from the official repository but also creating and distributing private libraries. This is very useful for reusing private code libraries within a company.

We can package compiled static/dynamic libraries into local packages or remote packages for distribution, or install them directly to the system directory.

## Create Library Project {#prepare-library-project}

First, we can use the `xmake create` command to quickly create an empty static or dynamic library project.

```bash
$ xmake create -t static test
create test ...
  [+]: xmake.lua
  [+]: src/foo.cpp
  [+]: src/foo.h
  [+]: src/main.cpp
  [+]: .gitignore
create ok!
```

The default generated `xmake.lua` is quite simple. We need to modify it slightly to add [`add_headerfiles`](/api/description/project-target.html#add_headerfiles) to export header files, so that the library headers can be installed together during installation.

```lua
add_rules("mode.debug", "mode.release")

target("foo")
    set_kind("static")
    add_files("src/foo.cpp")
    add_headerfiles("src/foo.h")

target("test")
    set_kind("binary")
    add_deps("foo")
    add_files("src/main.cpp")
```

By default, `add_headerfiles` installs header files directly to the `include` directory.

If you want to install header files to a subdirectory (e.g. `include/foo/foo.h`) to avoid filename conflicts, you can set `prefixdir`:

```lua
add_headerfiles("src/foo.h", {prefixdir = "foo"})
```

For more details, please refer to: [add\_headerfiles documentation](/api/description/project-target.html#add_headerfiles).

In addition to header files, we can also use [`add_installfiles`](/api/description/project-target.html#add_installfiles) to install any other files, such as documentation, scripts, resource files, etc.

```lua
-- Install readme.md to share/doc/foo directory
add_installfiles("readme.md", {prefixdir = "share/doc/foo"})

-- Install all files under assets
add_installfiles("assets/**", {prefixdir = "share/foo/assets"})
```

## Distribute as Local Package

If our library is only used within the local LAN or shared with others via a network drive, and does not need to be deployed to a remote git repository, we can use local package distribution.

The advantages of local packages are:

* No need to set up a Git repository
* Pre-compiled binaries are distributed directly, resulting in fast integration
* Supports binary packages for multiple platforms, architectures, and build modes (Debug/Release)

### Packaging

Run the `xmake package` command (or the full command `xmake package -f local`) in the root directory of the library project to package it.

```bash
$ xmake package
checking for platform ... macosx 
checking for architecture ... x86_64 
checking for Xcode directory ... /Applications/Xcode.app 
checking for SDK version of Xcode for macosx (x86_64) ... 15.2 
checking for Minimal target version of Xcode for macosx (x86_64) ... 15.2 
[ 23%]: cache compiling.release src/main.cpp 
[ 23%]: cache compiling.release src/foo.cpp 
[ 35%]: archiving.release libfoo.a 
[ 71%]: linking.release test 
[100%]: build ok, spent 3.31s 
installing foo to build/packages/f/foo/macosx/x86_64/release .. 
package(foo): build/packages/f/foo generated 
installing test to build/packages/t/test/macosx/x86_64/release .. 
package(test): build/packages/t/test generated 
```

By default, it will be generated in the `build/packages` directory.

```
build/packages/
├── f 
│   └── foo 
│       ├── macosx 
│       │   └── x86_64 
│       │       └── release 
│       │           ├── include 
│       │           │   └── foo.h 
│       │           └── lib 
│       │               └── libfoo.a 
│       └── xmake.lua 
└── t 
    └── test 
        ├── macosx 
        │   └── x86_64 
        │       └── release 
        │           └── bin 
        │               └── test 
        └── xmake.lua 
```

Each package directory contains the generated binary library files (`.a`/`.lib`/`.so`/`.dll`) and header files.

### Consume Local Package {#local-package-integration}

We copy the generated `build/packages` directory to any location, or use it directly. Then configure it in the consumer project's `xmake.lua`:

```lua
add_rules("mode.debug", "mode.release")

-- Add local package repository directory, pointing to the packages directory
add_repositories("local-repo /path/to/test/build/packages")

-- Import foo package
add_requires("foo")

target("bar")
    set_kind("binary")
    add_files("src/*.cpp")
    add_packages("foo")
```

Here we use several interfaces:

* [`add_repositories`](/api/description/global-interfaces.html#add_repositories): Add a custom package repository. The first argument `local-repo` is the repository name, and the second argument is the repository address (here it is a local path).
* [`add_requires`](/api/description/global-interfaces.html#add_requires): Declare the packages that the project depends on.
* [`add_packages`](/api/description/project-target.html#add_packages): Link the specified packages to the current target.

::: tip Repository vs Package
We need to distinguish between **Repository** and **Package**:

* **Repository**: A collection of package description files. It can maintain and manage multiple packages.
* **Package**: A specific library or tool (e.g., `foo`, `zlib`).

A repository can contain multiple packages, and their organization structure is usually as follows (classified by the first letter):

```
repository/
└── packages/
    ├── f/
    │   ├── foo/
    │   │   └── xmake.lua
    │   └── bar/
    │       └── xmake.lua
    └── z/
        └── zlib/
            └── xmake.lua
```

The `build/packages` directory generated by `xmake package` mentioned above is actually a directory structure that conforms to the Xmake repository specification. Therefore, we can import it as a repository via `add_repositories`, and Xmake will automatically search for the `foo` package we need in it.
:::

When executing `xmake` to build, Xmake will link the corresponding binary libraries directly from the local repository.

## Distribute Remote Package {#distribute-as-remote-package}

If we need to manage versions and distribute via a git repository, we can use the remote package mode. It supports distributing both source packages and binary packages.

The advantages of remote packages are:

* Version control based on Git
* Supports source distribution (automatic compilation) and binary distribution (direct installation)
* Support for multi-version switching

### Configure Remote Package {#generate-package-configuration}

We run `xmake package -f remote` to generate a configuration template for the remote package.

```bash
$ xmake package -f remote
```

It will generate the `packages/f/foo/xmake.lua` file. We can modify it as needed to support source distribution or binary distribution.

#### Source Distribution

This is the most common way. We only need to configure the git repository address, and Xmake will automatically download the source code and compile and install it.

```lua
package("foo")
    set_description("The foo package")
    set_license("Apache-2.0")

    -- Set private git repository address
    add_urls("git@github.com:mycompany/foo.git")
    add_versions("1.0", "<commit-sha>")

    on_install(function (package)
        local configs = {}
        if package:config("shared") then
            configs.kind = "shared"
        end
        import("package.tools.xmake").install(package, configs)
    end)
```

#### Binary Distribution

If we don't want to leak source code, or want to speed up installation, we can pre-compile binary packages (e.g. `.tar.gz`), upload them to a server, and then configure the download address.

```lua
package("foo")
    set_description("The foo package")

    -- Set pre-compiled binary package address
    add_urls("https://example.com/releases/foo-$(version).tar.gz")
    add_versions("1.0", "<shasum>")

    on_install(function (package)
        -- Install binary files directly
        os.cp("include", package:installdir())
        os.cp("lib", package:installdir())
    end)
```

For more detailed package configuration parameters, please refer to: [Package Configuration](/guide/package-management/package-distribution.html#define-package-configuration) and [Package Dependency API](/api/description/package-dependencies.html).

In addition, we can also refer to the existing package configurations in the official repository [xmake-repo](https://github.com/xmake-io/xmake-repo).

We need to create a private git repository (e.g., `my-repo`) to store all package configurations. Push the generated `packages` directory to this repository.

The directory structure is similar to:

```
my-repo/
└── packages/
    └── f/
        └── foo/
            └── xmake.lua
```

### Consume Remote Package {#remote-package-integration}

In the consumer project, we need to add this private repository.

```lua
add_rules("mode.debug", "mode.release")

-- Add private Git repository
add_repositories("my-repo git@github.com:mycompany/my-repo.git")

add_requires("foo")

target("bar")
    set_kind("binary")
    add_files("src/*.cpp")
    add_packages("foo")
```

Xmake will automatically pull the package description from the `my-repo` repository, and then download the `foo` source code according to `add_urls` for compilation and installation.

## Distribute C++ Modules Package {#distribute-cxx-modules}

Xmake also supports distributing C++ Modules libraries.

### Prepare Module Library {#prepare-module-library}

If it is a pure module library, we recommend configuring `set_kind("moduleonly")` in the project `xmake.lua` and exporting module files like `.mpp`.

```lua
target("foo")
    set_kind("moduleonly")
    add_files("src/*.mpp")
```

### Define Module Package {#define-module-package}

In the package description, we need to set `set_kind("library", {moduleonly = true})`. This tells Xmake to treat it as a pure module package, which does not require conventional library linking and handles module dependencies better.

```lua
package("foo")
    set_kind("library", {moduleonly = true})
    set_sourcedir(path.join(os.scriptdir(), "src"))

    on_install(function(package)
        import("package.tools.xmake").install(package, {})
    end)
```

### Consume Module Package {#consume-module-package}

When using module packages, we need to enable C++20 module build support.

```lua
add_repositories("my-repo git@github.com:mycompany/my-repo.git")
add_requires("foo")

target("bar")
    set_kind("binary")
    set_languages("c++20")
    add_packages("foo")
    -- Enable C++ module build policy
    set_policy("build.c++.modules", true)
```

For more complete examples, please refer to: [C++ Modules Package Distribution Example](https://github.com/xmake-io/xmake/tree/master/tests/projects/c%2B%2B/modules/packages).

## Manage Package Repositories {#repository-management}

Whether it is a remote package or a local package, we can flexibly choose how to manage the package repository.

### Project Internal Maintenance {#project-internal-maintenance}

If it is a private package within the project and does not need to be shared across projects, we can place the package repository directly under the project directory.

For example, we create a `packages` directory in the project root directory as a repository:

```
projectdir/
├── packages/
│   └── f/
│       └── foo/
│           └── xmake.lua
├── src/
│   └── main.cpp
└── xmake.lua
```

Then add this repository in `xmake.lua` via `add_repositories` (relative paths are supported):

```lua
add_repositories("my-repo packages")
add_requires("foo")

target("test")
    set_kind("binary")
    add_files("src/*.cpp")
    add_packages("foo")
```

In this way, Xmake will automatically look for the `foo` package configuration in the `packages` directory under the current project.

### Private Git Repository {#private-git-repository}

If you need to share packages among multiple projects within the company, establishing an independent Git repository (such as GitHub private repository, GitLab, Gitee, or company intranet Git) to maintain package configurations is a better choice.

We can import the git repository address directly via `add_repositories`:

```lua
add_repositories("my-repo git@github.com:mycompany/my-repo.git")
```

If the repository is private, please ensure that the local environment has configured SSH Key or has access permissions.

In addition, we can also use the `xrepo add-repo` or `xmake repo --add` command to add the repository address.

`xrepo` is a global independent command, while `xmake repo` can add package repositories only in the local project without affecting other projects.

```bash
# Add globally
$ xrepo add-repo my-repo git@github.com:mycompany/my-repo.git

# Add only for the current project
$ xmake repo --add my-repo git@github.com:mycompany/my-repo.git
```

### Official Repository {#official-repository}

If your package is open source and you want to share it with all Xmake users, you can submit it to the official [xmake-repo](https://github.com/xmake-io/xmake-repo) repository. For specific contribution guidelines, please refer to: [Submit Packages to Official Repository](/guide/package-management/package-distribution.html#submit-packages-to-the-official-repository).

## Install to System {#install-to-system}

In addition to packaging and distribution, during the development and debugging stage, or if we want to install the library directly to the system directory for other projects to use, we can run `xmake install` directly.

```bash
$ xmake install
```

By default, it will install to the system directory. If you want to install to a specific directory, you can specify the output directory:

```bash
$ xmake install -o /tmp/output
```

After installation, the directory structure is roughly as follows:

```
/tmp/output
├── include
│   └── foo.h
├── lib
│   ├── libfoo.a
│   └── pkgconfig
│       └── foo.pc
└── share
    └── cmake
        └── modules
            └── foo-config.cmake
```

Since we configured the `utils.install.pkgconfig_importfiles` and `utils.install.cmake_importfiles` rules (see [Use in Other Build Systems](#use-in-other-build-systems)), `foo.pc` and `foo-config.cmake` files will be automatically generated during installation.

In this way, other non-xmake third-party projects (such as CMake projects) can also find and integrate it via `find_package(foo)`.

## Integrate with Other Build Systems {#use-in-other-build-systems}

If we are developing a library that needs to be used by other non-xmake projects, we can integrate it in the following ways.

### Use CMake (Xrepo) {#use-in-cmake-via-xrepo}

If it is a CMake project, we can use [xrepo-cmake](https://github.com/xmake-io/xrepo-cmake) to directly integrate packages managed by Xmake.

```cmake
# Download xrepo.cmake
if(NOT EXISTS "${CMAKE_BINARY_DIR}/xrepo.cmake")
    file(DOWNLOAD "https://raw.githubusercontent.com/xmake-io/xrepo-cmake/main/xrepo.cmake"
                  "${CMAKE_BINARY_DIR}/xrepo.cmake" TLS_VERIFY ON)
endif()
include(${CMAKE_BINARY_DIR}/xrepo.cmake)

# Import package
xrepo_package("foo")

# Link package
target_link_libraries(demo PRIVATE foo)
```

For packages in private repositories, we need to ensure that the corresponding repository has been added locally (`xrepo add-repo myrepo ...`).

For more detailed instructions, please refer to: [Using Xmake Packages in CMake](/guide/package-management/using-packages-in-cmake.html).

### Use CMake/Pkg-config {#use-in-cmake-pkgconfig}

We can also configure `utils.install.pkgconfig_importfiles` and `utils.install.cmake_importfiles` rules to generate import files while installing the library.

```lua
target("foo")
    set_kind("static")
    add_files("src/foo.cpp")
    add_headerfiles("src/foo.h")
    
    -- Export pkgconfig/cmake import files
    add_rules("utils.install.pkgconfig_importfiles")
    add_rules("utils.install.cmake_importfiles")
```

In this way, after users execute `xmake install` to install the library to the system, they can directly use standard methods to find and use the library.

**CMake**

```cmake
find_package(foo REQUIRED)
target_link_libraries(demo PRIVATE foo::foo)
```

**Pkg-config**

```bash
pkg-config --cflags --libs foo
```

## Generate Installation Package (XPack) {#generate-installation-package}

Xmake also supports using the [XPack](/guide/basic-commands/pack-programs.html#xpack) plugin to generate installation packages in various formats, such as NSIS, Deb, RPM, Zip, etc.

This is very useful for distributing binary SDKs or deploying to production environments.

### Supported Formats

* **Windows**: `nsis`, `wix`, `zip`, `targz`
* **Linux**: `deb`, `rpm`, `srpm`, `runself` (shell self-extracting script), `targz`, `srczip`, `appimage`
* **MacOS**: `dmg`, `zip`, `targz`, `runself`

### Configuration Example

We can add an `xpack` configuration block in `xmake.lua` to define packaging rules.

For example, to configure generating an NSIS installer:

```lua
-- Include xpack plugin
includes("@builtin/xpack")

target("foo")
    set_kind("shared")
    add_files("src/*.cpp")
    add_headerfiles("src/*.h")

xpack("foo")
    set_formats("nsis")
    set_title("Foo Library")
    set_description("The foo library package")
    set_author("ruki")
    set_version("1.0.0")
    
    -- Add targets to package
    add_targets("foo")
    
    -- Add other files
    add_installfiles("doc/*.md", {prefixdir = "share/doc/foo"})
```

Then execute the packaging command:

```bash
$ xmake pack
```

It will automatically download the NSIS tool and generate the installation package. The generated installation package can be installed by double-clicking, and it automatically configures environment variables such as PATH, making it convenient for users to use.

For more details, please see the documentation: [XPack Packaging](/guide/extensions/builtin-plugins.html#xpack).
