本文目标
- 使用自己写的动态库
 - 使用第三方库
 - 更新 
cm 
使用自己的动态库
写一个简单的库
目录结构
F:\2023\code\cmake\calc>tree /f
卷 dox 的文件夹 PATH 列表
卷序列号为 34D2-6BE8
F:.
│  CMakeLists.txt
│
├─include
│  └─calc
│          calc.h
│
└─src
        calc.cpp
        CMakeLists.txt
F:\2023\code\cmake\calc>
 
源码
include/calc/calc.h
#ifndef  _CALC_H_
#define  _CALC_H_
class Calc
{
public:
    Calc();
    ~Calc();
    int add(int a, int b);
};
#endif // _CALC_H_
 
src/calc.cpp
#include "calc/calc.h"
Calc::Calc()
{
}
Calc::~Calc()
{
}
int Calc::add(int a, int b)
{
    return a + b;
}
 
CMakeLists.txt
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(calc CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_subdirectory(src)
 
src/CMakeLists.txt
include_directories(${PROJECT_SOURCE_DIR}/include)
aux_source_directory(. CALC_SRCS)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
add_library(${PROJECT_NAME} SHARED ${CALC_SRCS})
set_target_properties(${PROJECT_NAME} PROPERTIES VERSION 1.0 SOVERSION 1)
 
生成动态库
F:\2023\code\cmake\calc>cmake -S . -G "Unix Makefiles" -B build && cmake --build build
-- The CXX compiler identification is GNU 10.3.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/program/tdmgcc/bin/g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: F:/2023/code/cmake/calc/build
[ 50%] Building CXX object src/CMakeFiles/calc.dir/calc.cpp.obj
[100%] Linking CXX shared library F:/2023/code/cmake/calc/lib/libcalc.dll
[100%] Built target calc
F:\2023\code\cmake\calc>dir
 驱动器 F 中的卷是 dox
 卷的序列号是 34D2-6BE8
 F:\2023\code\cmake\calc 的目录
2023/01/25  03:03    <DIR>          .
2023/01/25  03:03    <DIR>          ..
2023/01/25  03:03    <DIR>          build
2023/01/25  02:57               150 CMakeLists.txt
2023/01/25  02:57    <DIR>          include
2023/01/25  03:03    <DIR>          lib
2023/01/25  02:58    <DIR>          src
               1 个文件            150 字节
               6 个目录 91,635,671,040 可用字节
F:\2023\code\cmake\calc>cd lib
F:\2023\code\cmake\calc\lib>dir
 驱动器 F 中的卷是 dox
 卷的序列号是 34D2-6BE8
 F:\2023\code\cmake\calc\lib 的目录
2023/01/25  03:03    <DIR>          .
2023/01/25  03:03    <DIR>          ..
2023/01/25  03:03            99,384 libcalc.dll
2023/01/25  03:03             3,844 libcalc.dll.a
               2 个文件        103,228 字节
               2 个目录 91,635,671,040 可用字节
F:\2023\code\cmake\calc\lib>
 
硬编码的方式使用
c++
#include <iostream>
#include <memory>
#include "calc/calc.h"
int main()
{
    auto calc = std::make_unique<Calc>();
    std::cout << "1 + 2 = " << calc->add(1,2) << std::endl;
    std::cout << "hello world" << std::endl;
    return 0;
}
 
CMakeLists.txt
# 该项目所需 cmake 的最小版本, 如果 cmake 版本小于设置的版本,  cmake 将停止处理并报错
cmake_minimum_required(VERSION 3.0)
project(hello_cmake CXX)
set(CMAKE_BUILD_TYPE DEBUG)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# 检查是否定义了环境变量
if(NOT DEFINED ENV{calc_root})
    message(FATAL_ERROR "not defined environment variable:calc_root")
endif()
# calc 根目录
set(calc_root_dir $ENV{calc_root})
# calc 库目录
set(calc_lib_dir ${calc_root_dir}/lib)
# calc 头文件目录
set(calc_include_dir ${calc_root_dir}/include)
# 连接库的头文件
include_directories(${calc_include_dir})
# 指定链接库目录
link_directories(${calc_lib_dir})
# 库名称
set(lib_calc_name calc)
# 库文件完整名称 windows 为 libcalc.dll , linux 为 libcalc.so
set(lib_calc_full_name ${CMAKE_SHARED_LIBRARY_PREFIX}calc${CMAKE_SHARED_LIBRARY_SUFFIX})
aux_source_directory(. MAIN_SRCS)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
add_executable(${PROJECT_NAME} ${MAIN_SRCS})
# 链接库文件
target_link_libraries(${PROJECT_NAME} ${lib_calc_name})
# 复制库文件, 
# 只有 windows 下需要, 当然如果把 calc.dll 复制到系统目录倒也不用复制
if(${CMAKE_HOST_WIN32})
    add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy ${calc_lib_dir}/${lib_calc_full_name} ${PROJECT_SOURCE_DIR}/bin/${lib_calc_full_name})
endif()
 
windows 验证
F:\2023\code\cmake\hello_cmake>set calc_root=
F:\2023\code\cmake\hello_cmake>cmake -S . -G "Unix Makefiles" -B build && cmake --build build
CMake Error at CMakeLists.txt:12 (message):
  not defined environment variable:calc_root
-- Configuring incomplete, errors occurred!
See also "F:/2023/code/cmake/hello_cmake/build/CMakeFiles/CMakeOutput.log".
F:\2023\code\cmake\hello_cmake>set calc_root=F:/2023/code/cmake/calc
F:\2023\code\cmake\hello_cmake>cmake -S . -G "Unix Makefiles" -B build && cmake --build build
-- Configuring done
-- Generating done
-- Build files have been written to: F:/2023/code/cmake/hello_cmake/build
[100%] Built target hello_cmake
F:\2023\code\cmake\hello_cmake>dir bin
 驱动器 F 中的卷是 dox
 卷的序列号是 34D2-6BE8
 F:\2023\code\cmake\hello_cmake\bin 的目录
2023/01/25  04:08    <DIR>          .
2023/01/25  04:08    <DIR>          ..
2023/01/25  04:08         2,929,130 hello_cmake.exe
2023/01/25  04:08            99,384 libcalc.dll
               2 个文件      3,028,514 字节
               2 个目录 91,583,438,848 可用字节
F:\2023\code\cmake\hello_cmake>.\bin\hello_cmake.exe
1 + 2 = 3
hello world
F:\2023\code\cmake\hello_cmake>
 
linux 验证
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ unset calc_root
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ cmake -S . -B build && cmake --build build
CMake Error at CMakeLists.txt:12 (message):
  not defined environment variable:calc_root
-- Configuring incomplete, errors occurred!
See also "/home/ubuntu/code/cmake/hello_cmake/build/CMakeFiles/CMakeOutput.log".
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ export calc_root=/home/ubuntu/code/cmake/calc
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ cmake -S . -B build && cmake --build build
-- Configuring done
-- Generating done
-- Build files have been written to: /home/ubuntu/code/cmake/hello_cmake/build
[ 50%] Building CXX object CMakeFiles/hello_cmake.dir/main.cpp.o
[100%] Linking CXX executable /home/ubuntu/code/cmake/hello_cmake/bin/hello_cmake
[100%] Built target hello_cmake
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ ll bin
total 68
drwxrwxr-x 2 ubuntu ubuntu  4096 Jan 25 04:24 ./
drwxrwxr-x 4 ubuntu ubuntu  4096 Jan 25 04:24 ../
-rwxrwxr-x 1 ubuntu ubuntu 58440 Jan 25 04:24 hello_cmake*
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ ./bin/hello_cmake 
1 + 2 = 3
hello world
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ 
 
find_package 的方式
其实上面的硬编码只是硬编码了 calc_root 这个变量, cmake 脚本在 windows 和 linux 已经是通用的了, 而且使用的时候有检查环境变量. 但是如果有好多个库要使用, 那么上面的方式就不太适用了. 此时可以用 find_package 来解决此问题
 推荐参考:
 cmake(三十二)Cmake之find_package指令
 cmake(7):find_package命令详解
 cmake教程4(find_package使用)
目录结构
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ tree -a
.
├── CMakeLists.txt
├── cmake
│   └── FindCALC.cmake
└── main.cpp
1 directory, 3 files
ubuntu@ubuntu-cpp:~/code/cmake/hello_cmake$ 
 
CMakeLists.txt
CMakeLists.txt
# 该项目所需 cmake 的最小版本, 如果 cmake 版本小于设置的版本,  cmake 将停止处理并报错
cmake_minimum_required(VERSION 3.25)
project(hello_cmake CXX)
set(CMAKE_BUILD_TYPE DEBUG)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# 设置模块搜索目录
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
aux_source_directory(. MAIN_SRCS)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
add_executable(${PROJECT_NAME} ${MAIN_SRCS})
# 如果有  Policy CMP0074 is not set: find_package uses <PackageName>_ROOT variables. 警告
# 则参考: https://blog.csdn.net/yzlh2009/article/details/116428378 解决, 本文直接提升 cmake_minimum_required 为当前版本
set(calc_root $ENV{calc_root})
# 查找 calc 库
find_package(CALC MODULE REQUIRED)
if(CALC_FOUND)
    include_directories(${calc_include_dir})
    target_link_libraries(${PROJECT_NAME} ${calc_library})
endif()
# 复制库文件, 
# 只有 windows 下需要, 当然如果把 calc.dll 复制到系统目录倒也不用复制
if(${CMAKE_HOST_WIN32})
    add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy ${calc_lib_dir}/${lib_calc_full_name} ${PROJECT_SOURCE_DIR}/bin/${lib_calc_full_name})
endif()
 
cmake/FindCALC.cmake
注意: FindCALC.cmake 规则为 FindPackageName.cmake , 其中 PackageName 为全大写
# calc 根目录
set(calc_root_dir ${calc_root})
set(calc_include_dir ${calc_root_dir}/include)
set(calc_lib_dir ${calc_root_dir}/lib)
message(STATUS "info - calc_root_dir : ${calc_root_dir}")
message(STATUS "info - calc_include_dir : ${calc_include_dir}")
message(STATUS "info - calc_lib_dir : ${calc_lib_dir}")
# 指定链接库目录
link_directories(${calc_lib_dir})
# 库名称
set(lib_calc_name calc)
# 库文件完整名称 windows 为 libcalc.dll , linux 为 libcalc.so
set(lib_calc_full_name ${CMAKE_SHARED_LIBRARY_PREFIX}calc${CMAKE_SHARED_LIBRARY_SUFFIX})
message(STATUS "info - lib_calc_name : ${lib_calc_name}")
message(STATUS "info - lib_calc_full_name : ${lib_calc_full_name}")
# 查找头文件
find_path(calc_include_dir calc.h PATHS "${calc_include_dir}")
# 查找库文件
find_library(calc_library calc PATHS "${calc_lib_dir}")
message(STATUS "info - calc_include_dir : ${calc_include_dir}")
message(STATUS "info - calc_library : ${calc_library}")
# 如果找到
if(calc_include_dir AND calc_library)
    set(CALC_FOUND TRUE)
    message(STATUS "Found calc: ${calc_library}")
endif()
# 如果没有找到, 并且 calc 为必须依赖项
if(NOT CALC_FOUND AND CALC_FIND_REQUIRED)
    message(FATAL_ERROR "Coluld not find calc")
endif()
 
验证
linux 大同小异, 不再展示
F:\2023\code\cmake\hello_cmake>cmake -S . -G "Unix Makefiles" -B build && cmake --build build
-- The CXX compiler identification is GNU 10.3.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: D:/program/tdmgcc/bin/g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- info - calc_root_dir : F:/2023/code/cmake/calc
-- info - calc_include_dir : F:/2023/code/cmake/calc/include
-- info - calc_lib_dir : F:/2023/code/cmake/calc/lib
-- info - lib_calc_name : calc
-- info - lib_calc_full_name : libcalc.dll
-- info - calc_include_dir : F:/2023/code/cmake/calc/include
-- info - calc_library : F:/2023/code/cmake/calc/lib/libcalc.dll.a
-- Found calc: F:/2023/code/cmake/calc/lib/libcalc.dll.a
-- Configuring done
-- Generating done
-- Build files have been written to: F:/2023/code/cmake/hello_cmake/build
[ 50%] Building CXX object CMakeFiles/hello_cmake.dir/main.cpp.obj
[100%] Linking CXX executable F:/2023/code/cmake/hello_cmake/bin/hello_cmake.exe
[100%] Built target hello_cmake
F:\2023\code\cmake\hello_cmake>dir bin
 驱动器 F 中的卷是 dox
 卷的序列号是 34D2-6BE8
 F:\2023\code\cmake\hello_cmake\bin 的目录
2023/01/25  05:49    <DIR>          .
2023/01/25  05:49    <DIR>          ..
2023/01/25  05:49         2,929,130 hello_cmake.exe
2023/01/25  05:49            99,384 libcalc.dll
               2 个文件      3,028,514 字节
               2 个目录 91,582,947,328 可用字节
F:\2023\code\cmake\hello_cmake>.\bin\hello_cmake.exe
1 + 2 = 3
hello world
F:\2023\code\cmake\hello_cmake>
 
上述操作有什么问题
- calc 库的头文件应当合并成1个, 这样引入的时候不用写那么多的 include
 - 复制库文件部分应当写成一个函数, 这样调用方直接调用这个函数就好了
 - 只验证了 tdm-gcc(windows) 和 g++(linux), 未验证 msvc
 - 没有区分 debug 和 release
 
修正 find_package 脚本
- 修正自定义库头文件布局
 - 添加两个库, 一个为必须依赖, 一个为可选依赖
 - 添加复制库文件的函数
 - 验证 msvc (windows) , tdm-gcc (windows) , g++ (linux)
 
第一个自定义库
此为必选依赖
第二个自定义库
此为可选依赖
主程序
tdm-gcc (windows) 验证
msvc (windows) 验证
g++ (linux) 验证
使用 wxWidgets 写一个 Hello World
首要目标是在 linux 和 windows 上运行起来
代码
https://docs.wxwidgets.org/3.2/overview_helloworld.html
// wxWidgets "Hello World" Program
 
// For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h>
 
#ifndef WX_PRECOMP
    #include <wx/wx.h>
#endif
 
class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};
 
class MyFrame : public wxFrame
{
public:
    MyFrame();
 
private:
    void OnHello(wxCommandEvent& event);
    void OnExit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
};
 
enum
{
    ID_Hello = 1
};
 
wxIMPLEMENT_APP(MyApp);
 
bool MyApp::OnInit()
{
    MyFrame *frame = new MyFrame();
    frame->Show(true);
    return true;
}
 
MyFrame::MyFrame()
    : wxFrame(NULL, wxID_ANY, "Hello World")
{
    wxMenu *menuFile = new wxMenu;
    menuFile->Append(ID_Hello, "&Hello...\tCtrl-H",
                     "Help string shown in status bar for this menu item");
    menuFile->AppendSeparator();
    menuFile->Append(wxID_EXIT);
 
    wxMenu *menuHelp = new wxMenu;
    menuHelp->Append(wxID_ABOUT);
 
    wxMenuBar *menuBar = new wxMenuBar;
    menuBar->Append(menuFile, "&File");
    menuBar->Append(menuHelp, "&Help");
 
    SetMenuBar( menuBar );
 
    CreateStatusBar();
    SetStatusText("Welcome to wxWidgets!");
 
    Bind(wxEVT_MENU, &MyFrame::OnHello, this, ID_Hello);
    Bind(wxEVT_MENU, &MyFrame::OnAbout, this, wxID_ABOUT);
    Bind(wxEVT_MENU, &MyFrame::OnExit, this, wxID_EXIT);
}
 
void MyFrame::OnExit(wxCommandEvent& event)
{
    Close(true);
}
 
void MyFrame::OnAbout(wxCommandEvent& event)
{
    wxMessageBox("This is a wxWidgets Hello World example",
                 "About Hello World", wxOK | wxICON_INFORMATION);
}
 
void MyFrame::OnHello(wxCommandEvent& event)
{
    wxLogMessage("Hello world from wxWidgets!");
}
 
linux 版
安装
sudo apt-get install pkg-config
sudo apt install libgtk-3-dev
 
然后直接安装即可
./configure && make && sudo make install
 
hello world
编译
ubuntu@ubuntu-cpp:~/code/cmake/wx_test$ ll
total 164
drwxrwxr-x 2 ubuntu ubuntu   4096 Jan 25 02:33 ./
drwxrwxr-x 3 ubuntu ubuntu   4096 Jan 25 02:27 ../
-rwxrwxr-x 1 ubuntu ubuntu 155328 Jan 25 02:33 hello*
-rw-rw-r-- 1 ubuntu ubuntu   1707 Jan 25 02:27 main.cpp
ubuntu@ubuntu-cpp:~/code/cmake/wx_test$ 
 
运行起来的效果

windows 版
在 Windows 上的环境搭建也很简单, 参考:
 vs2019配置wxwidgets3.1.6教程
 VS2019配置wxWidgets v3.1.6开发环境(超详细)
 【配置】VS2015下wxWidgets 3.1.1开发环境
上述几篇博客已经写的很好, 不再赘述
cm 工具应当更新什么内容
需要添加
- 添加 clean 子命令
 - 添加 --add-module 子命令
 - 修正帮助文档的输出
 
待实现
- 全局配置和当前项目配置. 思路: 全局配置放在安装目录的 config 文件, 当前项目配置放在 .cm/config
 - 命令别名. 思路: 命令别名放在 .cm/config
 - 语言标准检测 思路: 提前准备几个特定的程序, 针对不同的标准进行验证
 - 与第三方库整合
 - doxygen 命令
 - test 命令
 


















