gradle-native
gradle-native copied to clipboard
Introduce guide for building native library
Similar to https://github.com/nokeedev/gradle-native/issues/626, the guide teaches the user how to build a library with Gradle and Nokee. There are 3 important sections: 1) simplest build creates a shared library, 2) targetLinkages
configuration to create a static only library or a dual linkage library and 3) how to use the library (via dependencies).
The goal of the guide is not to understand dependency management but to demonstrate the library can be used as intended.
0. Setup
$ mkdir -p demo/demo_lib
$ cd demo
$ echo "include 'demo_lib'" > demo/settings.gradle
1. Simplest build
Sources in src/main/c
, src/main/headers
(private headers), and src/main/public
(public headers, exported to consumers)
.demo_lib/build.gradle
plugins {
id 'dev.nokee.c-library'
}
The library is built into build/libs/main/libdemo_lib.dylib
(on macOS), build/libs/main/libdemo_lib.so
(on other *nix), and build/libs/main/demo_lib.dll
(on Windows). Additionally, Windows will produce a .lib
file side-by-side with the .dll
. This file represents the import library and contains the redirection to the correct ordinal of the shared library. This file may be absent if the shared library does not export any symbols (via __declspec(dllexport)
or .def
file). In this guide, we use declspec
on Windows. Some use cases may include using the shared library dynamically thus not requiring explicitly linking against the import library, which is not covered in this guide.
The object files are located in build/objs
and options.txt
are in build/tmp/<task-name>
.
2. Target linkages
.demo_lib/build.gradle
plugins {
id 'dev.nokee.c-library'
}
library {
targetLinkages = [linkages.static] // <1>
}
<1> targetLinkages
is a component dimension (ListProperty
). linkages
is the TargetLinkage
factory which create a static
or shared
linkage. Here, we set the targetLinkages
to a single element list with only the static
linkage.
It may be important to mention that linkages are "how the object files are linked together" either as a shared library (.dylib
, .so
, or .dll
) or static library (.a
, or .lib
)
The library is built into build/libs/main/libdemo_lib.a
(on *nix), and build/libs/main/demo_lib.lib
(on Windows). Not the .lib
on Windows is a static library, not an import library meaning the is no additional runtime requirement from the library aside from it's own shared library dependencies if any.
If we which to create a dual linkage library, we just have to set the targetLinkages
to a collection of both linkages:
.demo_lib/build.gradle
library {
targetLinkages = [linkages.static, linkages.shared]
}
3. Using the library
$ mkdir demo_app
$ echo "include 'demo_app' >> settings.gradle
.demo_app/build.gradle
plugins {
id 'dev.nokee.c-application'
}
application {
dependencies {
implementation project(':demo_lib') // <1>
}
}
<1> If only one linkage is declared, the build will pick that one. However, if multiple linkages are declared, the build will select the shared linkage by default.
To select the static linkage when both linkages are selected, we need to configure the dependency's attribute:
application {
dependencies {
implementation(project(':demo_lib')) {
attributes {
attribute(BinaryLinkage.BINARY_LINKAGE_ATTRIBUTE, objects.named(BinaryLinkage, "static"))
}
}
}
}
Open Question about this guide
Convenience for linkage configuration on dependency
Binary linkage on dependency may be a bit more complicated for first-time users. Maybe we should introduce a similar construct as DependencyHandler#platform
. Maybe something like implementation useStaticLibrary(project(':demo_lib'))
Configuration of dependency attributes is also error-prone and quite verbose.
Sub-project names
It's generally considered best practice to use sub-projects instead of using directly the root project. In this case, we want two projects: 1) the library (subject of the guide) and 2) an application (demonstrate how to use the library). Gradle's sample/guides often use lib
and app
for the project name but that would create file names like liblib.dylib
or worst lib.lib
which may be more confusing to the user. We could use project names like greeter
(library) and hello
(application) instead which better represent each project.
The challenge with this guide is to give a concise explanation of the shared library vs static library without going too much into the details. Nokee focus on building libraries not on how native libraries works (which differ a bit between OS). Unfortunately, it's a bit too common for beginners to not have a clear understanding of what are the various native components and how they work together. Understanding those basic concepts is outside the scope of this guide but we can at least give a bit of information so users with little to no experience can understand while more advanced users can focus on learning the concept Nokee users for building native components (in this case, libraries).