CMake best practice using shared libraries versions - linux

I'm organizing my "development policies in C" and distributing some codes in static and shared libs.
Static libs are ok, but I found a "gap" about shared libraries in documentation: How to specify the SOVERSION on "find_library".
At this moment I'm building libraries this way:
cmake_minimum_required (VERSION 2.8.11)
set (INSTALL_BIN_DIR "" CACHE PATH "full binary path")
set (INSTALL_LIB_DIR "$ENV{HOME}/embedded/llib/lib" CACHE PATH "full binary path")
set (INSTALL_INCLUDE_DIR "$ENV{HOME}/embedded/llib/include" CACHE PATH "full include path")
set (SRC_DIR "src" CACHE PATH "Source files path")
set (H_DIR "include" CACHE PATH "Source files path")
set (C_FILES )
list (
APPEND C_FILES
${SRC_DIR}/cJSON.c
)
set (H_FILES )
list (
APPEND H_FILES
${H_DIR}/cJSON.h
)
# Define Project name
project (cJSON)
# Create a library called "cJSON" which includes the source and header files.
add_library (cJSON SHARED "${C_FILES}")
#set_target_properties(cJSON PROPERTIES
# PUBLIC_HEADER "include/cJSON.h")
include_directories (include)
# Make sure the compiler can find include files for our Hello library
# when other libraries or executables link to Hello
#target_include_directories (cJSON PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties (cJSON
PROPERTIES
VERSION 1.0 SOVERSION 1
PUBLIC_HEADER "${H_FILES}"
)
install(TARGETS cJSON
# IMPORTANT: Add the foo library to the "export-set"
EXPORT cJSONTargets
LIBRARY
RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin
LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT shlib
PUBLIC_HEADER DESTINATION "${INSTALL_INCLUDE_DIR}" COMPONENT dev
)
Running cmake, make and make install it results in:
lrwxrwxrwx 1 takaite takaite 13 Dez 7 11:52 libcJSON.so -> libcJSON.so.1
lrwxrwxrwx 1 takaite takaite 15 Dez 7 11:52 libcJSON.so.1 -> libcJSON.so.1.0
-rw-r--r-- 1 takaite takaite 27194 Dez 7 15:03 libcJSON.so.1.0
And in another library, I'm including this way:
cmake_minimum_required (VERSION 2.8.11)
set (INSTALL_BIN_DIR "" CACHE PATH "full binary path")
set (INSTALL_LIB_DIR "$ENV{HOME}/embedded/llib/lib" CACHE PATH "full binary path")
set (INSTALL_INCLUDE_DIR "$ENV{HOME}/embedded/llib/include" CACHE PATH "full include path")
set (SRC_DIR "src" CACHE PATH "Source files path")
set (H_DIR "include" CACHE PATH "Source files path")
set (C_FILES )
list (
APPEND C_FILES
${SRC_DIR}/dict.c
)
set (H_FILES )
list (
APPEND H_FILES
${H_DIR}/dict.h
)
# Define Project name
project (dict)
set (CMAKE_FIND_LIBRARY_SUFFIXES_BKP ${CMAKE_FIND_LIBRARY_SUFFIXES})
# Set lib version to be used
set (CMAKE_FIND_LIBRARY_SUFFIXES ".so.1")
find_library (
CJSON_LIB
NAMES cJSON
PATHS ${INSTALL_LIB_DIR}
)
set (CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_BKP})
message ("cJSON_lib: ${CJSON_LIB}")
# Create a library called "cJSON" which includes the source and header files.
add_library (dict SHARED "${C_FILES}" ${CJSON_LIB})
include_directories (${H_DIR} ${INSTALL_INCLUDE_DIR})
# Make sure the compiler can find include files for our Hello library
# when other libraries or executables link to Hello
#target_include_directories (cJSON PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties (dict
PROPERTIES
VERSION 1.0 SOVERSION 1
PUBLIC_HEADER "${H_FILES}"
)
install(TARGETS dict
# IMPORTANT: Add the foo library to the "export-set"
EXPORT DictTargets
LIBRARY
RUNTIME DESTINATION "${INSTALL_BIN_DIR}" COMPONENT bin
LIBRARY DESTINATION "${INSTALL_LIB_DIR}" COMPONENT shlib
PUBLIC_HEADER DESTINATION "${INSTALL_INCLUDE_DIR}" COMPONENT dev
)
I can't believe this is the right way to do it. Could any one show me a better way?

For search specific soversion of library you can use precise filename in NAMES option for find_library:
find_library (
CJSON_LIB
NAMES libcJSON.so.1
PATHS ${INSTALL_LIB_DIR}
)
From the documentation for find_library:
Each library name given to the NAMES option is first considered as a library file name and then considered with platform-specific prefixes (e.g. lib) and suffixes (e.g. .so). Therefore one may specify library file names such as libfoo.a directly. This can be used to locate static libraries on UNIX-like systems.
Note, that different soversions of the same library are assumed to be ABI compatible with each other. So it is rarely needed to search specific soversion of the library.
Changes in the library, which introduce ABI incopatibility should be accompanied with changing library's version. E.g: libcJSON2.so. So you cannot accidentally find incompatible library using find_library.

Related

how to force SCons to build with relative paths?

I have the following project structure:
/project
/src_dirs
/src_dir_1
/...
/include_dirs
/inc_dir_1
/...
/output
SConstruct
/Sconscripts
lib1_sconscript
lib2_sconscript
/...
objects/
/...
libs/
/...
The build process invoked from the output directory. so all the paths in the sconscripts, are relative to output directory. my sconscript files are auto generated. as you can see below, the paths to source files and to include files are relative paths. this is a demo sconscript file:
Import('libaEnv')
includes = ['../../project/include_dirs/inc_dir_1/be/cmn/inc', '../../project/include_dirs/inc_dir_1/be/be/cmn/api_inc']
directives = ['-CC','-c','-g']
code_switches = ['FAST_RUNG_MLK', 'EN_PRIORITY']
listDefines = code_switches
linkLibs = []
crt = libaEnv.Object(target='objects/crt.o', source='../../project/src_dirs/src_dir_1/crt.c', CPPDEFINES=listDefines, CPPFLAGS=directives, CPPPATH=includes)
ert = libaEnv.Object(target='objects/ert.o', source='../../project/src_dirs/src_dir_1/ert.c', CPPDEFINES=listDefines, CPPFLAGS=directives, CPPPATH=includes)
urt = libaEnv.Object(target='objects/urt.o', source='../../project/src_dirs/src_dir_1/urt.c', CPPDEFINES=listDefines, CPPFLAGS=directives, CPPPATH=includes)
liba = libaEnv.Library (target='libs/liba.a', source=[crt,ert,urt])
Return('liba')
I have seen that scons invokes the compiler with absolute paths to the source and the headers files. i have seen this by running scons with -verbose (i have also validate this by printing the command line in Action.py in the spawn method).
My scons version is: SCons 2.5.1 and i am running with python 2.7.
How can i force scons to invoke the compiler with relative paths only ?
One approach here is you can use top-relative addressing, as in:
includes = ['#project/include_dirs/inc_dir_1/be/cmn/inc', '#project/include_dirs/inc_dir_1/be/be/cmn/api_inc']
This still gets you absolute paths, but they'll be computed based on a valid starting point (# = "the directory containing the top-level SConsctruct", thus top-relative)

conan.io: call exe with virtual run environment

I have a hello tool which contains only exe files (without source).
Hello tool structure:
bin
helloBin.exe
helloRoot.exe
conanfile.py
conanfile.py content:
class ToolHelloConan(ConanFile):
name = "ToolHello"
version = "0.1"
settings = "os", "compiler", "build_type", "arch"
def package(self):
self.copy("*")
def package_info(self):
self.cpp_info.libs = self.collect_libs()
I've exported the hello tool to local cache: conan export-pkg . ToolHello/0.1#user/testing. This copied all exe in local_cache/ToolHello/0.1/user/testing/package/hash/bin. The bin in local cache looks like this:
bin
helloBin.exe
helloRoot.exe
I've defined a tool integration project which contains only the conanfile.txt
[requires]
ToolHello/0.1#user/testing
[generators]
virtualrunenv
After running conan install . in tool integration project and activating the virtual run environment, I am able to call only the helloRoot.exe because it's located right in the bin directory, but I'm not able to execute the bin/bin/helloBin.exe
Question: How do I run exe files which are not located directly in the local_cache/ToolHello/0.1/user/testing/package/hash/bin, but in local_cache/ToolHello/0.1/user/testing/package/hash/bin/directory?
You need to define the bindirs that are not the default one (bin). Add this to your conanfile.py:
def package_info(self):
self.cpp_info.bindirs = ["bin", "bin/directory"]
If you need to also include the root of the package folder, you might need to use:
def package_info(self):
self.cpp_info.bindirs = ["", "bin", "bin/directory"]

How to set the path for module command?

This is my .modulepath file, the last two lines are the paths where I have my modules mounted from another hard drive. Even though I added these lines module avail command does not fetch me any of the modules in those folders. If anyone could help it would be of great help.
#
# #(#)$Id: 38aa24cc33a5f54a93781d63005a084f74418022 $
# Module version 3.2.10
# init/.modulespath. Generated from .modulespath.in by configure.
#
# Modulepath initial setup
# ========================
#
# This file defines the initial setup for the module files search path.
# Comments may be added anywhere, which begin on # and continue until the
# end of the line
# Each line containing a single path will be added to the MODULEPATH
# environment variable. You may add as many as you want - just
# limited by the maximum variable size of your shell.
#
/etc/environment-modules/modules
#/usr/share/modules/versions # location of version files
#/usr/Modules/$MODULE_VERSION/modulefiles # Module pkg modulefiles (if versioning)
#/usr/Modules/modulefiles # Module pkg modulefiles (if no versioning)
#/usr/share/modules/modulefiles # General module files
#/usr/Modules/3.2.10/your_contribs # Edit for your requirements
/opt/apps/modulefiles/Core
/opt/apps/modulefiles/Compiler
I have even tried using module use /opt/apps/modulesfiles/Core
user#user-N501VW:~$ module use /opt/apps/modulefiles/Core
user#user-N501VW:~$ $MODULEPATH
bash: /opt/apps/modulefiles/Core:/etc/environment-modules/modules:/usr/share/modules/versions:/usr/Modules/$MODULE_VERSION/modulefiles:/usr/share/modules/modulefiles: No such file or directory
akhila#akhila-N501VW:~$ module avail
------------------------------------------------------------- /usr/share/modules/versions --------------------------------------------------------------
3.2.10
------------------------------------------------------------ /usr/share/modules/modulefiles ------------------------------------------------------------
dot module-git module-info modules null use.own
Even though your specific modulepaths are correctly set in MODULEPATH environment variable, module avail does not return any modulefiles for these directories. It means module has not found a file in these directories that is a modulefile.
So I suggest you to:
check if your mountpoint is correctly mounted
verify that the files in the directories are modulefiles compatible with the module command you use (on the module command version you use, the content of a modulefile should start with the #%Module magic cookie)

scons fails to resolve relative source path

I have the following project structure:
/prj
SConstruct
/src
/app
/lib1
/lib2
/...
'/prj/src/lib1' structure:
/lib1
/src
/test
SConscript
'lib1/SConscript':
SConscript('test/test1/SConscript',
exports = 'env',
variant_dir = '#build/release/lib1/test',
duplicate = 0)
and, finally, 'test' directory:
/test
/common
helpers.cpp
/test1
SConscript
main.cpp
In 'test/test1/SConscript' sources specified as:
Sources = ['../common/helpers.cpp', 'main.cpp']
Result:
scons: *** [build/release/lib1/common/helpers.o]
Source `build/release/lib1/common/helpers.cpp' not found,
needed by target `build/release/lib1/common/helpers.o'
As can be seen the problem is that scons tries to find out the source file 'helpers.cpp' in build directory, not in source one.
Some research shows that the problem raised when source file path begins with '../'. When all sources defined underneath 'SConscript' file all is Ok.
Scons v2.5.1 and v3.0.1 demonstrate the same behavior.
What I did wrong? I've found this answer where the author advised:
You could use ../test.cpp as filename
but I doing exactly the same. Is such scons behavior intended or this is a bug?
Your "code" in "lib1/SConscript":
SConscript('test/test1/SConscript',
exports = 'env',
variant_dir = '#build/release/lib1/test',
duplicate = 0)
uses the name of the given "test/test1/SConscript" and implicitly links the folder "test/test1" as "variant folder" (=variant_dir) to the target directory "#build/release/lib1/test". So if a required file can't be found in "#build/release/lib1/test", SCons tries to do an alternative "lookup" in "test/test1/". But this link is not automatically set for the "common" folder as well, and that's why the lookup of the "helpers.cpp" fails. This is the intended behaviour and correct in SCons.
A solution for your current problem would be to move the "test/test1/SConscript" one folder level higher, include the sources there as "common/helpers.cpp" and "test/main.cpp" and call this new SConscript from "lib1/SConscript" as:
SConscript('test/SConscript',
exports = 'env',
variant_dir = '#build/release/lib1/test',
duplicate = 0)

CPM failed to get the hash for HEAD

I'm trying to use CMake for the following CMakeLists.txt:
cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR)
#-----------------------------------------------------------------------
# CPM configuration
#-----------------------------------------------------------------------
set(CPM_MODULE_NAME "arc_ball")
set(CPM_LIB_TARGET_NAME ${CPM_MODULE_NAME})
if ((DEFINED CPM_DIR) AND (DEFINED CPM_UNIQUE_ID) AND (DEFINED CPM_TARGET_NAME))
set(CPM_LIB_TARGET_NAME ${CPM_TARGET_NAME})
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CPM_DIR})
include(CPM)
else()
set (CPM_DIR "${CMAKE_CURRENT_BINARY_DIR}/cpm-packages" CACHE TYPE STRING)
find_package(Git)
if(NOT GIT_FOUND)
message(FATAL_ERROR "CPM requires Git.")
endif()
if (NOT EXISTS ${CPM_DIR}/CPM.cmake)
message(STATUS "Cloning repo (https://github.com/iauns/cpm)")
execute_process(
COMMAND "${GIT_EXECUTABLE}" clone git#github.com:iauns/cpm.git ${CPM_DIR}
RESULT_VARIABLE error_code
OUTPUT_QUIET ERROR_QUIET)
if(error_code)
message(FATAL_ERROR "CPM failed to get the hash for HEAD")
endif()
endif()
include(${CPM_DIR}/CPM.cmake)
endif()
#-----------------------------------------------------------------------
# CPM Modules
#-----------------------------------------------------------------------
# ++ MODULE: GLM
CPM_AddModule("GLM"
GIT_REPOSITORY "https://github.com/iauns/cpm-glm"
GIT_TAG "1.0.2"
USE_EXISTING_VER TRUE
EXPORT_MODULE TRUE # Use EXPORT_MODULE sparingly. We expose GLM's interface
) # through our own interface hence why we export it.
# This call will ensure all include directories and definitions are present
# in the target. These correspond to the modules that we added above.
CPM_InitModule(${CPM_MODULE_NAME})
#-----------------------------------------------------------------------
# Source
#-----------------------------------------------------------------------
# Globbing has some downsides, but the advantages outweigh the
# disadvantages.
file (GLOB Sources
"arc-ball/*.cpp"
"arc-ball/*.hpp"
)
#-----------------------------------------------------------------------
# Library setup
#-----------------------------------------------------------------------
# Build the library.
add_library(${CPM_LIB_TARGET_NAME} ${Sources})
if (NOT EMSCRIPTEN AND CPM_LIBRARIES)
target_link_libraries(${CPM_LIB_TARGET_NAME} ${CPM_LIBRARIES})
endif()
My system is windows 8.1 and I'm using Visual Studio 11 2012 as a generator. However when I try to configure, I get the following error:
CMake Error at
CMakeLists.txt:26 (message):
CPM failed to get the hash for HEAD
Meaning that it's happening on that line:COMMAND "${GIT_EXECUTABLE}" clone git#github.com:iauns/cpm.git ${CPM_DIR}
Would anyone know why?
Thanks in advance for the help.

Resources