zoukankan      html  css  js  c++  java
  • learn cmake

    cmake简介

    在cmake出现之前,在linuxiax下,大型软件系统一般使用make来控制编译过程,而在Windows下可能是用vs下一个project来构建。一个复杂的系统本身依赖关系就很麻烦,如果想把一个linux下的项目拿到Windows下编译,我们可能要重新建立vs工程,这将是一项乏味且令人讨厌的工作。

    cmake就是为了解决这个问题而生,同时他也使得控制软件编译过程变得更简单。其基本原理就是开发人员使用cmake的语法规则编写CMakeLists.txt,cmake executable根据该文件在linux下生产Makefile,在Windows下可能生成vs工程。然后再通过make命令编译、安装。开发人员不再需要自己去写Makefile了。

    cmake语法

    cmake的语法应该不算难,在初学者看来,至少比make要更user friendly一些。具体的语法可以参见cmake document。下面贴出开源项目muduo的root directory下的CMakeLists.txt,我在该文件中加入了一些comment,可以对cmake command有初步的映像。

    # for cmake version control, if cmake version lower than this,
    # cmake failed. Also this will call cmake_policy(VERSION, 2.6)
    # for bug control.
    # I see most of projects set this to 2.6
    cmake_minimum_required(VERSION 2.6)
    
    #project(<PROJECT-NAME> [LANGUAGES] [<language-name>...])
    #default C CXX
    #this must call (explict or implict)
    project(muduo C CXX)
    #enable ctest
    #will need add_test() command, may in subdirectory/CMakeList.txt
    enable_testing()
    
    if(NOT CMAKE_BUILD_TYPE)
      set(CMAKE_BUILD_TYPE "Release")
    endif()
    #Signatures of this command that specify a <value>... placeholder expect zero or more arguments. Multiple arguments will be joined as a ;-list to form the actual variable value to be set. Zero arguments will cause normal variables to be unset. See the unset() command to unset variables explicitly.
    set(CXX_FLAGS
     -g
     # -DVALGRIND
     # -DMUDUO_STD_STRING
     -DCHECK_PTHREAD_RETURN_VALUE
     -D_FILE_OFFSET_BITS=64
     -Wall
     -Wextra
     #-Werror
     -Wconversion
     -Wno-unused-parameter
     -Wold-style-cast
     -Woverloaded-virtual
     -Wpointer-arith
     -Wshadow
     -Wwrite-strings
     -march=native
     # -MMD
     # -std=c++0x
     -rdynamic
     )
    #list(LENGTH <list> <output variable>)
    #list(GET <list> <element index> [<element index> ...]
    #     <output variable>)
    #list(APPEND <list> [<element> ...])
    #list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regular_expression>)
    #list(FIND <list> <value> <output variable>)
    #list(INSERT <list> <element_index> <element> [<element> ...])
    #list(REMOVE_ITEM <list> <value> [<value> ...])
    #list(REMOVE_AT <list> <index> [<index> ...])
    #list(REMOVE_DUPLICATES <list>)
    #list(REVERSE <list>)
    #list(SORT <list>)
    if(CMAKE_BUILD_BITS EQUAL 32)
      list(APPEND CXX_FLAGS "-m32")
    endif()
    #replace all ";" in CXX_FLAGS with " " and output to CMAKE_CXX_FLAGS
    string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CXX_FLAGS}")
    
    set(CMAKE_CXX_COMPILER "g++")
    set(CMAKE_CXX_FLAGS_DEBUG "-O0")
    set(CMAKE_CXX_FLAGS_RELEASE "-O2 -finline-limit=1000 -DNDEBUG")
    set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
    set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
    # call /usr/share/cmake-3.5/Modules/FindBoost.cmake
    find_package(Boost REQUIRED)
    find_package(Protobuf)
    find_package(CURL)
    find_package(ZLIB)
    # find the path where ares.h in
    find_path(CARES_INCLUDE_DIR ares.h)
    find_library(CARES_LIBRARY NAMES cares)
    find_path(MHD_INCLUDE_DIR microhttpd.h)
    find_library(MHD_LIBRARY NAMES microhttpd)
    find_library(BOOSTTEST_LIBRARY NAMES boost_unit_test_framework)
    find_library(BOOSTPO_LIBRARY NAMES boost_program_options)
    find_path(TCMALLOC_INCLUDE_DIR gperftools/heap-profiler.h)
    find_library(TCMALLOC_LIBRARY NAMES tcmalloc_and_profiler)
    find_path(HIREDIS_INCLUDE_DIR hiredis/hiredis.h)
    find_library(HIREDIS_LIBRARY NAMES hiredis)
    find_path(GD_INCLUDE_DIR gd.h)
    find_library(GD_LIBRARY NAMES gd)
    find_program(THRIFT_COMPILER thrift)
    find_path(THRIFT_INCLUDE_DIR thrift)
    find_library(THRIFT_LIBRARY NAMES thrift)
    
    if(CARES_INCLUDE_DIR AND CARES_LIBRARY)
      message(STATUS "found cares")
    endif()
    if(CURL_FOUND)
      message(STATUS "found curl")
    endif()
    if(PROTOBUF_FOUND)
      message(STATUS "found protobuf")
    endif()
    if(TCMALLOC_INCLUDE_DIR AND TCMALLOC_LIBRARY)
      message(STATUS "found tcmalloc")
    endif()
    if(ZLIB_FOUND)
      message(STATUS "found zlib")
    endif()
    if(HIREDIS_INCLUDE_DIR AND HIREDIS_LIBRARY)
      message(STATUS "found hiredis")
    endif()
    if(GD_INCLUDE_DIR AND GD_LIBRARY)
      message(STATUS "found gd")
    endif()
    if(THRIFT_COMPILER AND THRIFT_INCLUDE_DIR AND THRIFT_LIBRARY)
      message(STATUS "found thrift")
    endif()
    
    include_directories(${Boost_INCLUDE_DIRS})
    
    include_directories(${PROJECT_SOURCE_DIR})
    
    string(TOUPPER ${CMAKE_BUILD_TYPE} BUILD_TYPE)
    message(STATUS "CXX_FLAGS = " ${CMAKE_CXX_FLAGS} " " ${CMAKE_CXX_FLAGS_${BUILD_TYPE}})
    
    add_subdirectory(muduo/base)
    add_subdirectory(muduo/net)
    
    if(NOT CMAKE_BUILD_NO_EXAMPLES)
      add_subdirectory(contrib)
      add_subdirectory(examples)
    else()
      if(CARES_INCLUDE_DIR AND CARES_LIBRARY)
        add_subdirectory(examples/cdns)
      endif()
    endif()
    
    

    cmake示例

    编译链接库

    构建lib应该算是一个最常见的需求,现在假设我们新建一个简单库,只包含一个整数相加的函数。我们有两个文件add.h和add.cc。

    //add.h
    int add(int a, int b);
    
    //add.cc
    #include"add.h"
    
    int add(int a, int b)
    {
        return a + b;
    }
    

    我们可以新建CMakeLists.txt如下

    cmake_minimum_required(VERSION 2.6)
    project(add)
    set (add_SRCS
        add.cc
        )
    add_library(add ${add_SRCS})
    
    install(TARGETS add DESTINATION lib)
    file(GLOB HEADERS "*.h")
    install(FILES ${HEADERS} DESTINATION include/add)
    

    这个命令不仅可以帮我们编译add这个lib,而且还可以将.a文件和.h文件安装到指令的目录下,这个由变量CMAKE_INSTALL_PREFIX控制,可用ccmake命令更改,default是/usr/local目录下。

    编译可执行文件

    现在假设我们要写一个程序,并且要使用上一步中的链接库,下面是程序代码及CMakeLists.txt

    //test.cc
    #include"add.h"
    
    #include<iostream>
    
    int main()
    {
        std::cout << add(1, 2) << std::endl;
    }
    
    cmake_minimum_required(VERSION 2.6)
    project(main)
    set (main_SRCS
        test.cc
        )
    include_directories("/home/keviwu/add/include/add")
    find_library(LIB_PATH add "/home/keviwu/add/lib")
    
    if (NOT LIB_PATH)
        message("libadd.a not find")
    endif()
    
    add_executable(main ${main_SRCS})
    target_link_libraries(main ${LIB_PATH})
    
  • 相关阅读:
    linux驱动摸索 --驱动框架初始化(结合韦东山视频教程)
    LWIP的移植笔记
    linux命令大全
    Linux中断(interrupt)子系统之一:中断系统基本原理
    Linux内核中的jiffies及其作用介绍及jiffies等相关函数详解
    Linux下PCI设备驱动程序开发 --- PCI驱动程序实现(三)
    VC++定义全局变量及extern用法
    [转]VS 2012环境下使用MFC进行OpenGL编程
    [转]在C++中容易出现的#error No Target Architecture
    实例详解:MFC坐标轴实现
  • 原文地址:https://www.cnblogs.com/keviwu/p/7470859.html
Copyright © 2011-2022 走看看