Summary
Developing your own library in C++ is quite convenient, but making it usable for others can be a bit challenging. It requires understanding the CMake toolset. This article may seem simple, but I spent three days working on this issue. Perhaps I am a bit slow, and with limited learning ability, I will strengthen this area in the future.
Call Relationships

Project Directory Structure
[root@vbox sysutil]# tree
.
├── 3rd-party
│ └── tools
│ ├── build
│ ├── CMakeLists.txt
│ ├── include
│ │ └── sysutil.h
│ └── src
│ ├── CMakeLists.txt
│ ├── readme.txt
│ └── sysutil.cpp
├── build
├── CMakeLists.txt
├── include
│ └── sysutil.h
└── src
└── test.cpp
9 directories, 8 files
[root@vbox sysutil]#
sysutil/src/test.cpp
#include "sysutil.h"
#include <iostream>
int main()
{
std::cout << "current_home: " << getCwd() << std::endl;
return 0;
}
sysutil/include/sysutil.h
This header file is copied from the tools directory for convenience of use.
#ifndef SYSUTIL_H
#define SYSUTIL_H
#include <filesystem>
std::filesystem::path getCwd();
std::filesystem::path getHome();
#endif
sysutil/CMakeLists.txt
This CMakeLists.txt is crucial as it references the third-party library, which is my own library, for ease of use. The importance of independent and modular development is highlighted here.
# This statement specifies the minimum required CMake version to run this CMake script is 3.16. If the CMake version used is lower than 3.16, an error will be reported.
cmake_minimum_required(VERSION 3.16)
# The message function is used to output information during CMake configuration.
message(">>> CMAKE_CURRENT_SOURCE_DIR = ${CMAKE_CURRENT_SOURCE_DIR}")
message(">>> CMAKE_TOOLCHAIN_FILE = ${CMAKE_TOOLCHAIN_FILE}")
# CMAKE_C_FLAGS_DEBUG and CMAKE_CXX_FLAGS_DEBUG are the compilation options for C and C++ in debug mode.
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g ")
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g ")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
#set(LIBNAME tYaml):Sets the value of the variable LIBNAME to tYaml.
set(LIBNAME tYaml)
# Define the project name as tYaml, indicating that the project uses C and C++ languages
project(${LIBNAME} C CXX)
# include_directories function specifies the directories for the compiler to look for header files
include_directories(
./src
./include
./include/yaml-cpp
)
# set function sets the value of the variable SOURCES to src/main.cpp
set(SOURCES
src/test.cpp
)
# link_directories function specifies the directories for the linker to look for library files. Here, the lib directory is specified.
link_directories(
lib
)
# add_executable function creates an executable file
add_executable(${LIBNAME} ${SOURCES})
# Define the list of linked libraries
# set(LIBRARIES pthread
# yaml-cpp
# )
# Reference the third-party yaml-cpp library (downloaded offline)
include(FetchContent)
FetchContent_Declare(
tools
# GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git
# GIT_TAG 0.8.0
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd-party/tools
)
FetchContent_MakeAvailable(tools)
# FetchContent_Declare(
# ssh2
# # GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git
# # GIT_TAG 0.8.0
# SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd-party/libssh2-1.11.1
# )
# FetchContent_MakeAvailable(ssh2)
# FetchContent_Declare(
# spdlog
# # GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git
# # GIT_TAG 0.8.0
# SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rd-party/spdlog-1.x
# )
# FetchContent_MakeAvailable(spdlog)
target_link_libraries(${LIBNAME} PUBLIC sysutil)
# target_link_libraries(${LIBNAME} PUBLIC pq)
#target_link_libraries(${LIBNAME} PUBLIC ssh2)
# target_link_libraries(${LIBNAME} PRIVATE spdlog::spdlog)
# target_link_libraries function links the libraries specified by the LIBRARIES variable (pthread and yaml-cpp) to the executable file specified by the LIBNAME variable (tYaml).
# target_link_libraries(${LIBNAME} ${LIBRARIES})
sysutil/3rd-party/tools/CMakeLists.txt
The most important function of this CMakeLists.txt is the entry file. It introduces the src directory.
message(STATUS "--------- begin cmake ---------")
PROJECT(sysutil)
cmake_minimum_required(VERSION 3.7)
message(STATUS "Using CMake version ${CMAKE_VERSION}")
add_subdirectory(src)
message(STATUS "--------- end cmake ---------")
sysutil/3rd-party/tools/include/sysutil.h
The header file is designed for ease of use by others.
#ifndef SYSUTIL_H
#define SYSUTIL_H
#include <filesystem>
std::filesystem::path getCwd();
std::filesystem::path getHome();
#endif
sysutil/3rd-party/tools/src/sysutil.cpp
The real work is done here, implementing the functionality.
#ifdef _WIN32
#include <Shlobj.h>
#ifdef _MSC_VER
#pragma comment(lib, "shell32.lib")
#pragma comment(lib, "ole32.lib")
#endif
#else
#include <pwd.h>
#include <unistd.h>
#endif
#include <cstdlib>
#include <filesystem>
#include <iostream>
std::filesystem::path getCwd() {
return std::filesystem::current_path();
}
std::filesystem::path getHome() {
#ifdef _WIN32
if (auto homeEnv = _wgetenv(L"USERPROFILE")) {
return std::filesystem::path(homeEnv);
}
PWSTR buf{};
SHGetKnownFolderPath(FOLDERID_Profile, 0, nullptr, &buf);
std::filesystem::path result{buf};
CoTaskMemFree(buf);
return result;
#else
if (auto homeEnv = std::getenv("HOME")) {
return std::filesystem::path(homeEnv);
}
auto passwd = getpwuid(getuid());
return std::filesystem::path(passwd->pw_dir);
#endif
}
sysutil/3rd-party/tools/src/CMakeLists.txt
This CMakeLists.txt is for generating shared libraries.
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include)
SET(LIBHELLO_SRC sysutil.cpp)
ADD_LIBRARY(sysutil SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(sysutil_static STATIC ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES(sysutil PROPERTIES VERSION 1.2 SOVERSION 1)
SET_TARGET_PROPERTIES(sysutil_static PROPERTIES OUTPUT_NAME "sysutil")
Compilation and Installation
[root@vbox build]# cmake ..
>>> CMAKE_CURRENT_SOURCE_DIR = /root/ulility_private/training/sysutil
>>> CMAKE_TOOLCHAIN_FILE =
-- The C compiler identification is GNU 12.3.1
-- The CXX compiler identification is GNU 12.3.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- --------- begin cmake ---------
-- Using CMake version 3.27.9
-- --------- end cmake ---------
-- Configuring done (1.1s)
-- Generating done (0.0s)
-- Build files have been written to: /root/ulility_private/training/sysutil/build
[root@vbox build]# make
[ 16%] Building CXX object _deps/tools-build/src/CMakeFiles/sysutil.dir/sysutil.cpp.o
[ 33%] Linking CXX shared library libsysutil.so
[ 33%] Built target sysutil
[ 50%] Building CXX object CMakeFiles/tYaml.dir/src/test.cpp.o
[ 66%] Linking CXX executable tYaml
[ 66%] Built target tYaml
[ 83%] Building CXX object _deps/tools-build/src/CMakeFiles/sysutil_static.dir/sysutil.cpp.o
[100%] Linking CXX static library libsysutil.a
[100%] Built target sysutil_static
[root@vbox build]# ./tYaml
current_home: "/root/ulility_private/training/sysutil/build"
[root@vbox build]#