| Name | Last modified | Size | Description | |
|---|---|---|---|---|
| Parent Directory | - | |||
Adhering to consistent and meaningful coding conventions is crucial for maintaining readable and maintainable code. This document outlines the recommended coding conventions for Apache Celix development, including naming conventions, formatting, comments, control structures, functions and error handling.
Note that not all existing code adheres to these conventions. New code should adhere to these conventions and when possible, existing code should be updated to adhere to these conventions.
camelCase for variable names.celix_ prefix or celix:: (sub)namespace for global variables.* and ampersands & should be placed on the variable type name.snake_case for structure names._t postfix for structure typedef.celix_ prefix for structure names.typedef struct celix_<obj> celix_<obj>_t;
celix_ prefix._<obj>_ camelCase infix for the object/module name.camelCase for the function name.* should be placed on the variable type name.celix_<obj>_is<Value> and celix_<obj>_set<Value> for boolean valuescelix_<obj>_get<Value> and celix_<obj>_set<Value> for other valuescelix_<obj>_create function and destroyed using
a celix_<obj>_destroy function.celix_<obj>_create function should return a pointer to the object.celix_<obj>_destroy function should return a void and should be able to handle a NULL pointer.
celix_<obj>_destroy function can be more easily used in
error handling code.Examples:
long celix_bundleContext_installBundle(celix_bundle_context_t* ctx, const char* bundleUrl, bool autoStart)bool celix_utils_stringEquals(const char* a, const char* b)celix_status_t celix_utils_createDirectory(const char* path, bool failIfPresent, const char** errorOut)SNAKE_CASE for constant names.CELIX_ prefix for constant names.#define for constants.snake_case for enum type names.celix_ prefix for enum type names.SNAKE_CASE for enum value names.CELIX_ prefix for enum value names._e postfix - for the enumExample:
typedef enum celix_hash_map_key_type {
CELIX_HASH_MAP_STRING_KEY,
CELIX_HASH_MAP_LONG_KEY
} celix_hash_map_key_type_e;
SNAKE_CASE for macro names.CELIX_ prefix for macro names.snake_case for file names..h extension and source files with a .c extension.include, api or spi directory.private and src directory.src directory.gtest directory with its own CMakeLists.txt file and src directory.celix_ prefix for header file names.snake_case.celix:: prefixed aliases for the library.celix_ prefix.celix::shell_api)void* handle;) and the rest of the members are
function pointers.celix_status_t and if needed using an out parameter.true indicates success and false indicates failure.SNAKE_CASE, prefixed with CELIX_ and postfixed with _NAME.SNAKE_CASE, prefixed with CELIX_ and postfixed with _VERSION._t postfixExample:
//celix_foo.h
#include "celix_errno.h"
#define CELIX_FOO_NAME "celix_foo"
#define CELIX_FOO_VERSION 1.0.0
typedef struct celix_foo {
void* handle;
celix_status_t (*doFoo)(void* handle, char** outMsg);
} celix_foo_t;
snake_case for C bundle target names.celix_ prefix for C bundle target names.celix:: prefixed aliases for C bundle targets.snake_case for C bundle symbolic names.apache_celix_ prefix for C bundle symbolic names.Apache Celix prefix for C bundle names.celix_ prefix for C bundle filenames.celix/ for C bundle groups.Examples:
add_celix_bundle(my_bundle
SOURCES src/my_bundle.c
SYMBOLIC_NAME "apache_celix_my_bundle"
NAME "Apache Celix My Bundle"
FILENAME "celix_my_bundle"
VERSION "1.0.0"
GROUP "celix/my_bundle_group"
)
add_library(celix::my_bundle ALIAS my_bundle)
snake_case for namespace names.celix namespace.detail for implementation details.CamelCase (starting with a capital) for class names.celix:: namespace or sub celix:: namespace.camelCase for function names.celix:: namespace or sub celix:: namespace.* and ampersands & should be placed on the variable type name.SNAKE_CASE for constants.celix:: namespace or sub celix:: namespace.example:
namespace celix {
constexpr long FRAMEWORK_BUNDLE_ID = 0;
constexpr const char* const SERVICE_ID = "service.id";
}
CamelCase (starting with a capital) for enum types names.enum class instead of enum and if possible use std::int8_t as base type.SNAKE_CASE for enum values without a celix/class prefix. Note that for enum values no prefix is required
because enum class values are scoped.Example:
namespace celix {
enum class ServiceRegistrationState {
REGISTERING,
REGISTERED,
UNREGISTERING,
UNREGISTERED
};
}
CamelCase (starting with a capital) for file names..h extension and source files with a .cc extension.celix/Bundle.h, celix/dm/Component.h).include, api or spi directory.private and src directory.src directory.#pragma once header guard.CamelCase (starting with a capital).celix:: prefixed aliases for the library.celix::Promises and celix::PushStreams which requires C++17.Celix::framework) and the Apache Celix utils library (Celix::utils) can only
use header-only C++ files. This ensure that the framework and utils library can be used in C only projects and do
not introduce a C++ ABI.celix_ prefix.CamelCase (starting with a capital) for service names.celix:: namespace or sub celix:: namespace.static constexpr const char* const NAME to the service class, for the service name.static constexpr const char* const VERSION to the service class, for the service version.CamelCase for C++ bundle target names.Celix prefix for C++ bundle target names.celix:: prefixed aliases for C++ bundle targets.CamelCase for C++ bundle symbolic names.Apache_Celix_ prefix for C++ bundle symbolic names.Apache Celix prefix for C++ bundle names.celix_ prefix for C++ bundle filenames.celix/ for C++ bundle groups.Examples:
add_celix_bundle(MyBundle
SOURCES src/MyBundle.cc
SYMBOLIC_NAME "Apache_Celix_MyBundle"
NAME "Apache Celix My Bundle"
FILENAME "celix_MyBundle"
VERSION "1.0.0"
GROUP "celix/MyBundleGroup"
)
add_library(celix::MyBundle ALIAS MyBundle)
TestSuite postfix..cc extension.CamelCase (starting with a capital) and have a Test postfix.error_injector libraries) a separate test suite should be used.
ErrorInjectionTestSuite postfix should be used for the test fixture.TearDown function or destructor of the test fixture.@ instead of \ for doxygen commands.@brief command and a short description.@param commands also provide in, out, or in/out information.@return commands also provide a description of the return value.@section errors_section Errors) to document the
possible errors. Use man 2 write as an example for a good errors section.if, for, while, etc.) that are followed by a parenthesis.else, do, etc) that are followed by a brace.clang-format -i <file>.if, else if, and else statements to handle multiple conditions.switch statements for multiple conditions with a default case.while statements for loops that may not execute.do/while statements for loops that must execute at least once.for statements for loops with a known number of iterations.goto is not allowed, except for error handling in C (for C++ use RAII).goto statements.
CELIX_DO_IF, CELIX_GOTO_IF_NULL and CELIX_GOTO_IF_ERR
macros can also be used.celix_status_t and if needed using an out parameter.true indicates success and false indicates failure.celix_err functionality.For log levels use the following guidelines:
Example of error handling and logging:
celix_foo_t* celix_foo_create(celix_log_helper_t* logHelper) {
celix_foo_t* foo = calloc(1, sizeof(*foo));
if (!foo) {
goto create_enomem_err;
}
CELIX_GOTO_IF_ERR(create_mutex_err, celixThreadMutex_create(&foo->mutex, NULL));
foo->list = celix_arrayList_create();
foo->map = celix_longHashMap_create();
if (!foo->list || !foo->map) {
goto create_enomem_err;
}
return foo;
create_mutex_err:
celix_logHelper_log(logHelper, CELIX_LOG_LEVEL_ERROR, "Error creating mutex");
free(foo); //mutex not created, do not use celix_foo_destroy to prevent mutex destroy
return NULL;
create_enomem_err:
celix_logHelper_log(logHelper, CELIX_LOG_LEVEL_ERROR, "Error creating foo, out of memory");
celix_foo_destroy(foo); //note celix_foo_destroy can handle NULL
return NULL;
}
void celix_foo_destroy(celix_foo_t* foo) {
if (foo != NULL) {
//note reverse order of creation
celixThreadMutex_destroy(&foo->mutex);
celix_arrayList_destroy(foo->list);
celix_longHashMap_destroy(foo->map);
free(foo);
}
}
EI_TESTS cmake condition.TearDown function or destructor of the test fixture._cut postfix.set(MY_LIB_SOURCES ...)
set(MY_LIB_PUBLIC_LIBS ...)
set(MY_LIB_PRIVATE_LIBS ...)
add_library(my_lib SHARED ${MY_LIB_SOURCES})
target_link_libraries(my_lib PUBLIC ${MY_LIB_PUBLIC_LIBS} PRIVATE ${MY_LIB_PRIVATE_LIBS})
celix_target_hide_symbols(my_lib)
...
if (ENABLE_TESTING)
add_library(my_lib_cut STATIC ${MY_LIB_SOURCES})
target_link_libraries(my_lib_cut PUBLIC ${MY_LIB_PUBLIC_LIBS} ${MY_LIB_PRIVATE_LIBS})
target_include_directories(my_lib_cut PUBLIC
${CMAKE_CURRENT_LIST_DIR}/src
${CMAKE_CURRENT_LIST_DIR}/include
${CMAKE_BINARY_DIR}/celix/gen/includes/my_lib
)
endif ()
celix::Promises and celix::PushStreams which requires C++17.celix::framework and celix::utils must be header-only.For C and C++ shared libraries, the following target properties should be set:
VERSION should be set to the library version.SOVERSION should be set to the library major version.OUTPUT_NAME should be set to the library name and should contain a celix_ prefix.add_library(my_lib SHARED
src/my_lib.c)
set_target_properties(my_lib
PROPERTIES
VERSION 1.0.0
SOVERSION 1
OUTPUT_NAME celix_my_lib)
For C and C++ static libraries, the following target properties should be set:
POSITION_INDEPENDENT_CODE should be set to ON for static libraries.OUTPUT_NAME should be set to the library name and should contain a celix_ prefix.add_library(my_lib STATIC
src/my_lib.c)
set_target_properties(my_lib
PROPERTIES
POSITION_INDEPENDENT_CODE ON
OUTPUT_NAME celix_my_lib)
For Apache Celix shared libraries, symbol visibility should be configured using the CMake target
properties C_VISIBILITY_PRESET, CXX_VISIBILITY_PRESET and VISIBILITY_INLINES_HIDDEN and a generated export
header.
The C_VISIBILITY_PRESET and CXX_VISIBILITY_PRESET target properties can be used to configure the default visibility
of symbols in C and C++ code. The VISIBILITY_INLINES_HIDDEN property can be used to configure the visibility of
inline functions. The VISIBILITY_INLINES_HIDDEN property is only supported for C++ code.
The default visibility should be configured to hidden and symbols should be explicitly exported using the export
marcos from a generated export header. The export header can be generated using the CMake function
generate_export_header. Every library should have its own export header.
For shared libraries, this can be done using the following CMake code:
add_library(my_lib SHARED
src/my_lib.c)
set_target_properties(my_lib PROPERTIES
C_VISIBILITY_PRESET hidden
#For C++ shared libraries also configure CXX_VISIBILITY_PRESET
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN ON
OUTPUT_NAME celix_my_lib)
target_include_directories(my_lib
PUBLIC
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/celix/gen/includes/my_lib>
PRIVATE
src)
#generate export header
generate_export_header(my_lib
BASE_NAME "CELIX_MY_LIB"
EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/celix/gen/includes/my_lib/celix_my_lib_export.h")
#install
install(TARGETS my_lib EXPORT celix LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/celix_my_lib)
install(DIRECTORY include/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/celix_my_lib)
install(DIRECTORY ${CMAKE_BINARY_DIR}/celix/gen/includes/my_lib/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/celix_my_lib)
For bundle, symbol visibility will default be configured to hidden. This can be default by providing
the DO_NOT_CONFIGURE_SYMBOL_VISIBILITY option to the CMake add_celix_bundle function.
If symbol visibility is not configured in the add_celix_bundle, symbol visibility should be configured the same
way as a shared library.
add_celix_bundle(my_bundle
SOURCES src/my_bundle.c
SYMBOLIC_NAME "apache_celix_my_bundle"
NAME "Apache Celix My Bundle"
FILENAME "celix_my_bundle"
VERSION "1.0.0"
GROUP "celix/my_bundle_group"
)
add_library(celix::my_bundle ALIAS my_bundle)
feature/, hotfix branches with hotfix/, bugfix branches with bugfix/
and release branches with release/.feature/1234-add-feature.