cmake官方demo学习整理

2023-12-24 19:39:10

cmake官方demo学习整理

概述

想将iconv编译进自己的DLL, 顺便学了一下用CMake来构建工程.
CMake官方demo(12个demo)提供的功能, 有点复杂.
就学了前4个demo, 初步用CMake来构建程序, 基本够用.

整理后的CMakeDemo目录结构

$ tree
.
├── CMakeLists.txt
├── config.h.in
├── main.cpp
├── my_lib_math
│   ├── CMakeLists.txt
│   ├── my_math.cpp
│   ├── my_math.def
│   └── my_math.h
└── README.txt

1 directory, 8 files

主工程

CMakeLists.txt

# --------------------------------------------------------------------------------
# PROJECT_SOURCE_DIR 默认是主CMakeLists.txt所在目录
# PROJECT_BINARY_DIR 是CMake . 所在的目录(e.g. ./build/)

# --------------------------------------------------------------------------------
# 普通宏用set来定义, 在实现中就不能用#ifdef来判断这个宏了, 因为始终会为TRUE
# 如果是固定的宏, 都可以定义在CMakeLists.txt的头部
set(LINE_80 "--------------------------------------------------------------------------------")

# --------------------------------------------------------------------------------
message(NOTICE ${LINE_80})
message(NOTICE "/CMakeLists.txt begin")
message(NOTICE ${LINE_80})

# --------------------------------------------------------------------------------
# 编译用的CMake版本要求
cmake_minimum_required(VERSION 3.10)

# --------------------------------------------------------------------------------
# 项目名称
project(prjCMakeDemo VERSION 1.0.0.0)
message(STATUS "PROJECT_NAME = ${PROJECT_NAME}")

# --------------------------------------------------------------------------------
# C+=版本要求
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# --------------------------------------------------------------------------------
# 定义编译宏
# 如果是哟个option来定义宏(BOOL量的开关宏), 可以在CMakeGUI中操作宏的打开和关闭, 可以在实现中用#ifdef来判断宏是否存在
option(USE_MYMATH "使用自己的数学库" ON)

# 宏相关
if(USE_MYMATH)
    # 设置变量 - 自己的库名称
    set(MY_MATH_LIB_NAME my_lib_math)
    message (STATUS "MY_MATH_LIB_NAME = ${MY_MATH_LIB_NAME}")

    # 设置变量 - 自己的库全路径
    set(MY_MATH_LIB_DIR ${PROJECT_SOURCE_DIR}/my_lib_math)
    message (STATUS "MY_MATH_LIB_DIR = ${MY_MATH_LIB_DIR}")

    # endif 后面必须有() , e.g. endif(), 否则报错
endif()

# --------------------------------------------------------------------------------
# 更新配置文件模板到配置文件
# 让源码和CMake定义的宏之间能有交互
# 如果是要在配置模板中更新的宏, 如果还没定义, 可以在configure_file执行之前定义
configure_file(Config.h.in ${PROJECT_SOURCE_DIR}/include/Config.h)

# --------------------------------------------------------------------------------
# 在addexe之前, 必须先添加子工程的CMakeLits.txt. 否则在addexe之后连接库时, 会找不到库
if(USE_MYMATH)
    # 如果使用了库, 就添加库工程的CMakeLists.txt
    add_subdirectory(${MY_MATH_LIB_DIR})
endif()

# --------------------------------------------------------------------------------
# 添加此工程的头文件包含路径
set(MY_PRJ_INCLUDES 
    "${PROJECT_SOURCE_DIR}" 
    "${PROJECT_SOURCE_DIR}/include"
    )

message(STATUS "MY_PRJ_INCLUDES = ${MY_PRJ_INCLUDES}")

# 添加此工程的包含路径
include_directories(
    ${MY_PRJ_INCLUDES}
)

# --------------------------------------------------------------------------------
# 更改exe输出路径为./bin
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

# 添加自己的工程为exe
add_executable(${PROJECT_NAME} main.cpp)

# --------------------------------------------------------------------------------
if(USE_MYMATH)
    # 包含库时的参数
    list(APPEND MY_PRJ_LIBS ${MY_MATH_LIB_NAME})
    message(STATUS "MY_PRJ_LIBS = ${MY_PRJ_LIBS}")

    # 库的包含路径, 由字库自己去设置给主工程用
    
    # target_link_libraries 参数:
    # 参数1 : 主工程的名称(要链接库到这个工程)
    # 参数2 : 要链接的库名称
    target_link_libraries(
    ${PROJECT_NAME}
    ${MY_PRJ_LIBS}
    )
endif()

message(NOTICE ${LINE_80})
message(NOTICE "/CMakeLists.txt END")
message(NOTICE ${LINE_80})

config.h.in

// @file config.h

#ifndef __CONFIG_H__
#define __CONFIG_H__

#define PROJECT_NAME "@PROJECT_NAME@"
#define PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define PROJECT_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define PROJECT_VERSION_TWEAK @PROJECT_VERSION_TWEAK@
#define PROJECT_FULL_VERSION_STRING "@PROJECT_NAME@ v@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@.@PROJECT_VERSION_PATCH@.@PROJECT_VERSION_TWEAK@"

// 如果在CMakeLists.txt中没有定义xx, #cmakedefine xx 就不会出现
// USE_MYMATH 是在CMakeLists.txt中用option定义出的开关宏
#cmakedefine USE_MYMATH

#endif // #ifndef __CONFIG_H__

main.cpp

#include <iostream> // for std::cout
#include <cmath> // for sqrt

#include "config.h"

#ifdef USE_MYMATH
#  include "my_math.h"
#endif

const char* get_prjoect_full_version()
{
  return PROJECT_FULL_VERSION_STRING;
}

int main(int argc, char* argv[])
{
  #ifdef USE_MYMATH
  printf("USE_MYMATH\r\n");
#else
  printf("NOT_USE_MYMATH\r\n");
#endif

  printf("%s v%d.%d.%d.%d\n", 
    PROJECT_NAME,
    PROJECT_VERSION_MAJOR,
    PROJECT_VERSION_MINOR,
    PROJECT_VERSION_PATCH,
    PROJECT_VERSION_TWEAK);

  if (argc < 2) {
    printf("%s\n", get_prjoect_full_version());
    std::cout << "Usage: " << argv[0] << " number" << std::endl;
    return 1;
  }

  const double inputValue = atof(argv[1]);

#ifdef USE_MYMATH
  const double outputValue = mysqrt(inputValue);
#else
  const double outputValue = sqrt(inputValue);
#endif

  std::cout << "The square root of " << inputValue << " is " << outputValue
            << std::endl;
  return 0;
}

README.txt

# @file README.txt

# --------------------------------------------------------------------------------
# how to build
# --------------------------------------------------------------------------------
clear && mkdir ./build && cd ./build
clear && rm ./* -rf && cmake .. && cmake --build .

DLL工程

CMakeLists.txt

# @file my_lib_math/CMakeLists.txt

# --------------------------------------------------------------------------------
# 子工程可以用父工程定义的宏, 在自己的工程中不用重复定义. e.g. LINE_80

# --------------------------------------------------------------------------------
message(NOTICE ${LINE_80})
message(NOTICE "/my_lib_math/CMakeLists.txt begin")
message(NOTICE ${LINE_80})

# --------------------------------------------------------------------------------
# 更改库工程输出目录为./bin
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

# 添加自己的工程为库
# add_library(<name> [STATIC | SHARED | MODULE]
# add_library 参数2可选项, STATIC 为静态库, SHARE 为动态库. 如果不写, 默认为静态库
add_library(my_lib_math SHARED my_math.cpp)

# --------------------------------------------------------------------------------
# 在库的CMakeLists.txt中添加库包含路径时, 库路径前必须有 INTERFACE, 否则报错
target_include_directories(
    my_lib_math
    INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
    )

# --------------------------------------------------------------------------------
message(NOTICE ${LINE_80})
message(NOTICE "/my_lib_math/CMakeLists.txt END")
message(NOTICE ${LINE_80})

my_math.cpp

// @file my_math.cpp

#include "my_math.h"

#include <iostream>

double mysqrt(double x)
{
  if (x <= 0) {
    return 0;
  }

  double result = x;

  // do ten iterations
  for (int i = 0; i < 10; ++i) {
    if (result <= 0) {
      result = 0.1;
    }
    double delta = x - (result * result);
    result = result + 0.5 * delta / result;
    std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
  }
  return result;
}

void _stdcall my_dll_fn(void)
{
    
}

my_math.h

// @file my_math.h

#ifndef __MY_MATH_H__
#define __MY_MATH_H__

double mysqrt(double x);

#endif // #ifndef __MY_MATH_H__

my_math.def

LIBRARY my_lib_math
; dll export function define

VERSION     1.0

EXPORTS
        mysqrt  @2
        my_dll_fn @1

备注

用VS做DLL, 只有标记哪个函数要导出才会导出.
用cygwin64 + cmake, 默认是将DLL工程中所有函数都导出了. 函数暴露的有点多.
本来想着隐藏DLL中的导出函数, 但是加入.def不好使, 全部导出了. 以后再研究.

END

文章来源:https://blog.csdn.net/LostSpeed/article/details/135184506
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。