Skip to content

About

Native libs common

Resources

Stars

12 stars

Watchers

8 watching

Forks

Repository files navigation

Native libs common stuff

Prerequisites

  • Conan C++ package manager 2.0.4 or higher
  • CMake 3.24 or higher
  • GCC 9 or higher / Clang 8 or higher

Build

Linux

mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -GNinja \
    -DCMAKE_C_COMPILER=clang \
    -DCMAKE_CXX_COMPILER=clang++ \
    -DCMAKE_CXX_FLAGS="-stdlib=libc++"  \
    ..

Windows

mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ^
    -DCMAKE_C_FLAGS_DEBUG=/MT ^
    -DCMAKE_CXX_FLAGS_DEBUG=/MT ^
    -G Ninja ^
    ..

macOS

mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -GNinja \
    -DCMAKE_C_COMPILER=clang \
    -DCMAKE_CXX_COMPILER=clang++ \
    -DCMAKE_CXX_FLAGS="-stdlib=libc++" \
    ..

Cross-compiling with zig

zig can be used as a self-contained cross-compiler via its cc / c++ subcommands, which removes the need for a separate cross toolchain:

mkdir build && cd build
cmake -DCMAKE_C_COMPILER="zig;cc;-target;x86_64-linux-musl" \
    -DCMAKE_CXX_COMPILER="zig;c++;-target;x86_64-linux-musl" \
    -DCMAKE_BUILD_TYPE=RelWithDebInfo \
    -DCMAKE_SYSTEM_NAME=Linux \
    -DCMAKE_SYSTEM_PROCESSOR=x86_64 \
    -DCMAKE_CROSSCOMPILING=ON \
    -GNinja \
    ..

CMAKE_SYSTEM_PROCESSOR must match the -target architecture: it is the only source for the Conan arch setting. Without it, arch is inherited from the build machine's default profile, and Conan would resolve dependencies for the host architecture while zig compiles for the target.

The compiler must be passed as a CMake list (zig;cc;-target;...), since zig cc is a subcommand rather than a standalone binary. Conan's compiler_executables accepts only an argument-less executable, so cmake/conan_provider.cmake detects this form and generates wrapper scripts in ${CMAKE_BINARY_DIR}/zig-wrappers/ that re-attach the subcommand and target, then points the Conan profile at those. The wrappers are named after the target triple, following the usual cross-toolchain convention, so build systems that infer cross-compilation from the compiler name recognise them:

zig-wrappers/x86_64-linux-musl-cc
zig-wrappers/x86_64-linux-musl-c++

Two settings distinguish zig builds from ordinary ones:

  • compiler.libcxx is left out of the profile, as zig supplies its own libc++ per target.
  • os.ag_cc_is_zig=1 is added, so packages built with zig get their own package ID instead of colliding with packages built by a plain clang of the same version.

Currently, it contains Conan recipes for AdGuard libs

Testing

Build All Tests

# Configure the project (if not done already)
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug

# Build all tests
cmake --build build --target tests

Run All Tests

# Run all tests using CTest
ctest --test-dir build --verbose

Run Specific Tests

# Run a specific test executable directly
./build/common/network_monitor_test

How to use conan

Conan is a C++ package manager. It is similar to maven, but stores recipes and binaries separately. Binaries can be uploaded to a repo and reused.

It is recommended to use the custom remote repo as the main repo (-i 0). Conan looks up binaries in the repo from which recipes were downloaded. So if a recipe is from conan-center, you won't be able to store binaries because it has the highest priority by default.

conan remote add --index 0 $REMOTE_NAME https://$ARTIFACTORY_HOST/artifactory/api/conan/$REPO_NAME

We customized some packages, so they need to be exported to local conan repository.

./scripts/export_conan.sh

If you want to upload built binaries and recipes to conan remote repository, use following command:

conan upload -r $REMOTE_NAME -c '*'

If you want to upload exported only recipes to conan remote repository, use following command:

conan upload -r $REMOTE_NAME -c '*' --only-recipe

Testing changes as a dependency

To test local changes in the library when it is used as a Conan package dependency, export a recipe and point the dependent project at it. Use conan export (not conan create) so the package is built later with the dependent project's target profile rather than the default one.

  1. If the default vcs_url in <root>/conanfile.py is not suitable, change it accordingly.

  2. Export the current working tree as version local (the recipe stages the git-tracked working tree, so no commit or push is required):

    conan export . --version local
  3. In the dependent project, replace native_libs_common/1.0.0@adguard/oss with native_libs_common/local.

  4. Re-run the cmake command; the package is built with that project's profile. Note: after further changes, purge the cached copy before re-exporting: conan remove -c "native_libs_common/local".

Code style

Common

  1. Indentation is 4 spaces (imported files may have another indent).
  2. Code must be commented enough in terms of control flow. All public and big static methods should have a description in Doxygen format (/** */)
  3. Formatting rules. We use CLion basic rules. They are based on LLVM and Apple rules, and applies 4 spaces indentation by default. But there are also rules not related to indentation:
    • Binary operator are always separated by spaces from their operands (x + y)

    • Screen width: 120 symbols (not 80)

    • In function definition, operator block is started on function line int main(int argc, char **argv) {. However, int func() try { is prohibited. If it makes harder to read the code, next line may be empty:

          int very_long_function_definition(
                  int foo1234567890, int bar9876543210, int baz9999999999, 
                  int x4242424242, int y1010101010, int z0101010101) noexcept {
      
              do_smth();
          }
    • In loops and ifs, operator block is started on function line too. Single-line branches should be in operator braces too.

  4. Identifier prefixes other than p_, m_, g_ and _ is prohibited
  5. Don't use p prefix unless it is really needed. In most cases type of identifier says what is it.
  6. All new headers should contain #pragma once guard instead of #define one.

C

No new C code please.

C++

  1. Language standard - C++20 (-std=c++20)
  2. Class prefixes - use namespaces instead.
  3. Namespaces - root namespace is ag::, max depth is 2 (plus may be ::test). Namespace names are snake_cases.
  4. Class naming - Capital CamelCase (Rust-like)
  5. Using naming - Capital CamelCase. If it is wrapped pointer to type with snake_case, then it may be named snake_case_ptr.
  6. Instance naming - snake_case
  7. Member function, non-member variable and parameter naming - snake_case
  8. Member variable naming - m_snake_case, public members of struct are snake_case.
  9. Member access - m_something, or this->something if m_ is missing in name.
  10. Constants and enum values (static const, constexpr and defines) naming - CAPITAL_UNDER_SCORE
  11. Global variables - g_snake_case
  12. Includes order - Chromium-style: a. List of external headers in <> b. List of our public headers, alphabetically sorted, in "". If current unit is implementation of the public header, that include should anyway be included here. c. List of current directory headers, alphabetically sorted, in "". This section should not exist in public headers.

Code example:

#pragma once

#include <string>

namespace ag::utils {
    class Strings {
    public:
        /**
         * Make greeting to the world
         * @param x Some random value
         * @return The greeting
         */
        static std::string hello_world(int x);
    }
}
#include <string>

#include "common/utils.h"

#include "another_utils.h"

namespace ag::utils {
    std::string Strings::hello_world(int x) {
        if (x % 2) {
            return "Hello, world!!";
        } else {
            return "Hello, world!1";
        }
    }
}

Doxygen comments

  • All public methods and functions should be documented.
  • Use Javadoc style with an autobrief feature.
  • autobrief means that the first statement of a long description automatically becomes a brief description. So @brief is redundant.
  • Use @return, not @returns
  • Use [out] in @param only if code is not self-explanatory.
  • Don't use [in] in @param.
  • Don't use extra line endings.
  • Use infinitive instead of the third person in brief descriptions.
  • Descriptions should start with a capital letter.

Examples:

/**
 * Sum of x and y.
 * This function is usually used to get sum of x and y.
 * @param x The x
 * @param yy The y
 * @return Sum of x and y.
int plus(int x, int yy) {
    return x + yy;
}
enum class t {
    A, /**< One-line post-identifier comment */
    /** Another one-line comment */
    B,
    /** Third one-line comment */
    C,
    D, /**< One-line post-identifier comment */
}

About

Native libs common

Resources

Stars

12 stars

Watchers

8 watching

Forks

Releases

Packages

Used by

Contributors

Languages