Aurora Linking Libs

Aurora Linking Libs

The project is an example of connecting libraries in different ways and with different build systems.

RU | EN

AuroraLinkingLibs

Description

The application is an example of linking libraries in various ways on the Aurora OS. The main goal is to demonstrate how to link static and dynamic libraries in all available application build systems for the Aurora OS. The application includes the ability to check the connection of three custom-written libraries: a static library, a implicit dynamic library, and a explicit dynamic library.

Build status:

  • example - pipeline status
  • dev - pipeline status

Table of Contents

Detailed description

There are three main ways to link any library:

  1. Take the library sources and integrate them directly into your project. This is the simplest method, but in this case the library will be rebuilt every time. And this can greatly reduce the speed of building the application.

  2. Use static libraries that are linked during application compilation. They are in files with the extension *.a

  3. Use dynamic libraries that are connected during application runtime. They are in files with the extension *.so

Next, we will show how to collect and connect libraries for all the methods described above on two build systems - qmake and cmake

Creating a library

For example, let's make the same library containing a single function that displays the sum of two numbers.

void print_add(int a, int b) {
    qDebug() << a << " + " << b << " = " << a + b;
}

Next, we need the corresponding *.pro and CMakeLists.txt files, which will configure the qmake and cmake builds respectively.

For qmake:

TEMPLATE = lib
TARGET = add

SOURCES += add.cpp \

HEADERS += add.h \

this code will build a dynamic library with a *.so file. To build a static one, you need to add a config after specifying the target:

TEMPLATE = lib
TARGET = add

CONFIG += staticlib

SOURCES += add.cpp \

HEADERS += add.h \

To build for the target, you need to go to Aurora IDE, make a dummy spec file in the rpm directory and start the build. The assembly will fail, but the library will be assembled and we will get what we need.

Next for cmake:

cmake_minimum_required(VERSION 3.0)
project(add)

# Find the Qt5 package
find_package(Qt5 COMPONENTS Core REQUIRED)

# Add the source files to the executable
add_library(add STATIC
    add.cpp
    add.h
)

# Include the header files
target_include_directories(add PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}
)

# Link against the Qt5 libraries
target_link_libraries(add PRIVATE
    Qt5::Core
)

For a dynamic library, replace STATIC with SHARED

Building the library

There are two ways to build the library: through the IDE and through the terminal

Building via IDE

  • In the case of qmake, it is enough to write a dummy spec file, which will describe how to build the rpm package. We start the assembly through the IDE. It will fail because... There will be nothing to load into rpm, but the library will be assembled. And we will get the desired *.a or *.so file.

  • In the case of cmake this will not work and you need to make a template application in which this library will be connected accordingly:

add_subdirectory(<library directory>)

Build via terminal

  1. Assembly within a specific target. Login to docker/virtualbox on port 2222 with the command:

    ssh -p 2222 -i "aurora-path"/vmshare/ssh/private_keys/sdk mersdk@localhost

Where "aurora-path" - path to the Aurora SDK installation directory

  1. Checking installed targets:

    sdk-assistant list
  2. Go to target

    as user:

    sb2 -t AuroraOS-4.0.2.303-base-armv7hl -m sdk-build

    as root:

    sb2 -t "$target" -m sdk-install -R

Accordingly, we change the target AuroraOS-4.0.2.303-base-armv7hl to the desired one. We go to the build directory and execute the commands as if we were building as on regular Linux.

  • For qmake:

    mkdir build
    cd build
    qmake ..
    make

    or call qmake of a specific target

    qmake <name>.pro
  • For cmake:

    mkdir build
    cd build
    cmake ..
    make

Linking the library to the application

Let's look at each of the ways to connect the library:

Building with sources

In this case, you can simply copy the library source files into the project and add them to the target via add_executable or SOURCE += for cmake and qmake respectively.

Building with sources (alternative)

You can directly call the library build during assembly and connect it. To do this, use the following commands:

  • For cmake:

    add_subdirectory(<directory>)

    -call an assembly in a subdirectory

    target_include_directories(${PROJECT_NAME} PRIVATE
    
    <directory>
    )

    -add include pathes from directory

    target_link_libraries(${PROJECT_NAME}
    <library name>
    )

    -to link a static library file

  • For qmake:

    SUBDIRS += "directory path"

    -call an assembly in a subdirectory

    INCLUDEPATH += "path to .h files"

    -add include pathes from directory

    LIBS += -L"library path" -l"library name"

    -to link a static library file

Adding a static library.

The static library has a .a extension and is included in the project at build time. To do this you need:

  1. Specify where to get function/class declarations from For cmake include_directories For qmake INCLUDEPATH +=

  2. Specify where to get the compiled library sources from For cmake target_link_libraries For qmake LIBS += -L$$OUT_PWD/../<library path> -l<library name>

There are no more requirements, because... The library sources are already inside the executable file

Dynamic library

The dynamic library is connected while the application is running. There are two types of dynamic library linking: explicit and implicit linking.

Implicit dynamic linking of a dynamic library

Everything is identical to the static library, but the *.so library file must be supplied along with the executable file

To do this, we indicate in the .spec file so that it is copied to the desired directory. Example for the mul and sub libraries:

mkdir %{buildroot}/%{_datadir}/%{name}/lib/
cp -rf $PWD/mul/libmul.so* %{buildroot}/%{_datadir}/%{name}/lib/
cp -rf $PWD/sub/libsub.so* %{buildroot}/%{_datadir}/%{name}/lib/
%define __requires_exclude ^(libadd.*|libsub.*|libmul.*).*$
%define __provides_exclude_from ^%{_datadir}/%{name}/lib/.*$

In AuroraOS, a path like /usr/share/{package_name}/lib/* is standard for the libraries required for the application.

If there is no library in the specified path, the application will not start

Explicitly linking a dynamic library

It is not necessary to specify paths for declarations and for libraries. It is connected using the QLibrary class. Example:

    QLibrary myLib("/usr/share/ru.auroraos.qmake_libraries/lib/libmul.so");
    if (myLib.load()) {
        typedef void (*MyFunction)(int, int);
        MyFunction myFunction = (MyFunction) myLib.resolve("print_mul");
        if (myFunction) {
            qDebug() << "Function resolved successfully";

            // Call the function
            myFunction(2, 3);
        } else {
            qDebug() << "Failed to resolve function";
        }
    } else {
        qDebug() << "Failed to load library";
    }

Because QLibrary searches required function by name, you need to add following line to the library code:

#define DLL_PUBLIC __attribute__ ((visibility("default")))

extern "C" DLL_PUBLIC <your function>

This was done because, due to the presence of function overloading in C++, the name of the function in the library and the actual name by which the function will be searched in the SO file will be different. extern "C" specifies that the name must match.

To search for a library, you need to specify the full path, but this can be avoided by adding our library to ldconfig.

Compatibility

The application works correctly starting with Aurora OS 5.x.x and higher.

Build features

This project contains two subprojects, each of which contains an identical application but with different build systems. In cmake_libraries, the project is built using the CMakeLists.txt file. In qmake_libraries, the project is built using the file ru.auroraos.qmake_libraries.pro.

Branch info

Branches

Install and Build

The project is built in the usual way using the Aurora SDK. Documentation to build.

Screenshots

Screenshots

Usage options

Calling a Function from the Library

  • Click on one of the options, after which a function from the library will be executed and a transition to the results screen will occur.

  • After the message about successful execution, you can go back.

Exploring Ways to Link Libraries

From the source code of this project, you can learn how to link various libraries for the build systems CMake and QMake:

  • static

  • dynamic with explicit linking

  • dynamic with implicit linking

Project Structure

The project has a standard C++ and QML based application structure for the Aurora OS.

  • The application using qmake employs the qmake build system.

  • The application using cmake employs the cmake build system.

CMake Project Structure

The project has a standard structure for C++ and QML applications for the Aurora OS.

  • CMakeLists.txt the file describes the project structure for the cmake build system.
  • icons the directory contains application icons for supported screen resolutions.
  • add the directory contains sources of static library which linking to app
  • sub the directory contains sources of dynamic library which linking implicit to app
  • mul the directory contains sources of dynamic library which linking explicit to app
  • qml the directory contains the QML source code and user interface resources.
    • cover the directory contains implementations of application covers.
    • icons the directory contains additional user interface icons.
    • pages the directory contains application pages.
    • cmake_libraries.qml the file provides the application window implementation.
  • rpm the directory contains the rpm package build settings.
  • src the directory contains C++ source code.
    • main.cpp the file is the entry point to the application.
  • translations the directory contains the user interface translation files.
  • ru.auroraos.cmake_libraries.desktop the file defines the display and startup options for the application.

QMake Project Structure

The project has a standard structure for C++ and QML applications for the Aurora OS.

  • add the subproject contains sources of static library which linking to app
  • sub the subproject contains sources of dynamic library which linking implicit to app
  • mul the subproject contains sources of dynamic library which linking explicit to app app the subproject describes the application itself and has the following structure:
  • app.pro the file describes the project structure for the qmake build system.
  • icons the directory contains application icons for supported screen resolutions.
  • qml the directory contains the QML source code and user interface resources.
    • cover the directory contains implementations of application covers.
    • icons the directory contains additional user interface icons.
    • pages the directory contains application pages.
    • qmake_libraries.qml the file provides the application window implementation.
  • rpm the directory contains the rpm package build settings.
  • src the directory contains C++ source code.
    • main.cpp the file is the entry point to the application.
  • translations the directory contains the user interface translation files.

Terms of Use and Participation in Development

The project source code is provided under license, which allows its use in third-party applications.

The Participant Agreement governs the rights granted by the participants to the Open Mobile Platform Company.

Participant information is listed in the AUTHORS file.

The Code of Conduct is the current set of rules of the Open Mobile Platform Company, which communicates the expectations for interaction between community members when communicating and working on projects.