29 Mart 2018 Perşembe

CMake

Giriş
Linux'taki bir projeden CMake kullanarak Visual Studio 2012 projesi üretirken aldığım notlar aşağıda. Dizinin şöyle bir yapıda olduğunu varsayalım.

    ├── MyProject
       ├── CMakeLists.txt
       ├── include
          ├── aaa.h
          ├── aaaa.h
       └── src
           ├── aaa.cpp
           ├── aaaa.cpp
Bazı projelerde özel bir build dizini açılıyor. En üstteki CMakeLists.txt mi yoksa bu yapı mı daha iyi emin değilim.
|_MyProject
  |_build
  |_src
  |_inc

GUI
1. "Browse Source" ile kaynak kodun bulunduğu dizin seçilir. Kaynak kod dizininde CMakeLists.txt dosyası da bulunmalı
2. "Browse Build" ile .sln dosyasının nerede oluşturulacağı seçilir.
3. "Configure" ile generator seçilir. Örneğin Visual Studio 11 seçilir.
4. "Generate" düğmesi ile .sln oluşturulur

Komut Satırı
CMake Komut Satırı yazısına taşıdım.

Metodlar
cmake programlama diliyle o kadar fazla sayıda metod geliyor ki hepsini anlamak ve bilmek kolay değil. Kullandığım bazı metodlar şöyle. Büyük küçük fark etmiyor

cmake sürümü
İstersek en düşük cmake sürümünü belirtebiliriz. Şöyle yaparız.
CMAKE_MINIMUM_REQUIRED(VERSION 3.4.1)
project
Projenin adını belirtiriz. Aşağıdaki komut projenin adını atar. MyProject.sln dosyasını oluşturur
PROJECT( MyProject )
file
Sonra Projede kullanılan dosya isimleri belirlenir.
Örnek
Dosya isimleri mylist adlı listeye doldurmak için şöyle yaparız
file(GLOB_RECURSE mylist "./*.cpp" "./*.h")
Örnek
Öz yinelemeli olmasın istersek şöyle yaparız. Bu sefer SOURCE adlı listeye doldurulur.
file(GLOB SOURCES *.cpp)
Örnek
Bazı projeler dosya tiplerine göre listeler oluşturuyor. Bence gereksiz bir hareket.
file(GLOB_RECURSE CXX_SRCS src/*.cpp)
file(GLOB_RECURSE C_SRCS src/*.c)
file(GLOB_RECURSE HPP_HDRS src/*.hpp)
file(GLOB_RECURSE H_HDRS src/*.h)
Örnek
Dosyalar projeye eklenir. Şöyle yaparız.
# Configure source files for production code
file(GLOB SOURCES ../../sources/*.cpp)


# Tell the cmake what needs to be builded
add_executable( myProject ${SOURCES} )
find package
Belirtilen kütüphanalerin (.so veya .lib) kurulu olduğunu kontrol eder. Boost için şöyle yaparız.
FIND_PACKAGE(Boost 1.59.0 REQUIRED COMPONENTS system thread filesystem)
Çıktı olarak şunu görürüz.
-- Boost version: 1.59.0
-- Found the following Boost libraries:
--   system
--   thread
--   filesystem
Eğer sadece belli bir paketin kurulu olduğunu kontrol etmek istersek şöyle yaparız. Bu durum örneğin header only bir kütüphaneyi kullanacaksak işe yarar.
find_package(Boost REQUIRED)
İstersek sürüm numarası da verebiliriz.
find_package(Boost 1.58.0 REQUIRED)
add_compile_options
Şöyle yaparız. Eğer belli bir hedef için kullanmak istersek target_compile_options() ta kullanılabilir.
add_compile_options(-fno-rtti)
add_custom_command
Örnek
Şöyle yaparız.
add_custom_command(TARGET MyProject
  POST_BUILD
  COMMAND cp foo.h ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
)
Örnek
Visual Studio'da build sonrasında bazı kopyalama işlemleri için post build copy komutu şöyle yaparız.
ADD_CUSTOM_COMMAND(TARGET MyProject
  POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/*.ini ${PROJECT_BINARY_DIR}
)
add_custom_target
Çağırmak için şöyle yaparız.
cmake --build /path/to/build/directory --target copy_all
Şöyle yaparız.
add_custom_target (copy_all
  COMMAND ${CMAKE_SOURCE_DIR}/copy.sh ${files}
  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
add_definitions
Açıklaması şöyle. Bu komut ile add_compile_options() hep karışıyor.  add_definitions() preprocessor için, diğeri ise derleyiciye seçenek geçmek için.
add_definitions is meant to add preprocessor definitions.
Eğer lazımsa -D ile başlayan preprocessor seçeneklerini belirlenir.
ADD_DEFINITIONS(-D_WIN32_WINNT=0X600)
Şöyle yaparız.
add_definitions(-DBOOST_LOG_DYN_LINK)
add_executable
Kaynak kodlar bir set içinde toplanır. Sonra verilen kaynak kodları derlemek ve bir uygulama üretmek için şöyle yaparız.
set(SOURCES
    src/p2.c
    src/p1.h
    src/p1.c)
add_executable(myexe ${SOURCES})
Set'i oluşturmak için glob yapılabilir.
file(GLOB_RECURSE CXX_SRCS src/*.cpp)
file(GLOB_RECURSE C_SRCS src/*.c)
file(GLOB_RECURSE HPP_HDRS src/*.hpp)
file(GLOB_RECURSE H_HDRS src/*.h)
set(SRCS "${C_SRCS};${CXX_SRCS}")
set(HDRS "${H_HDRS};${HPP_HDRS}")

add_executable(monoRenderer ${SRCS} ${HDRS})
Eğer istersek kaynak dosyaları teker teker de elle yazabiliriz.
ADD_EXECUTABLE(myexe src/mangaMe.cpp)
add_library
CMake add_library yazısına taşıdım.

add_subdirectory
İki tane CMakeLists.txt dosyası olsun
CMakeLists.txt
src/
    CMakeLists.txt
    main.cpp
build/
src içindeki ikinci CMakeLists.txt dosyasının tetiklenmesi için şöyle yaparız.
#tell CMake that we have some source files located in the src directory
add_subdirectory(src)
include
Bir başka CMake dosyasını dahil etmek için kullanılır. Dahil edilen CMake içindeki metodlar da çağrılabilir. Şöyle yaparız.
# Conan setup
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
include_directories
Şöyle yaparız. Bu komut birden fazla kere çağrılabilir.
INCLUDE_DIRECTORIES(includes)
Bir değişkene atanan değeri kullanmak için şöyle yaparız.
set(BOOST_ROOT "C:/dev/tools/boost_1_60_0")
include_directories(${INCLUDE_DIRECTORIES} ${BOOST_ROOT} include)
install - Target
Şöyle yaparız.
install(TARGETS helloworld
            RUNTIME DESTINATION ../build)
install - Custom
Söz dizimi şöyle
install([[SCRIPT <file>] [CODE <code>]]
        [COMPONENT <component>] [...])
Açıklaması şöyle
The SCRIPT form will invoke the given CMake script files during installation. If the script file name is a relative path it will be interpreted with respect to the current source directory. The CODE form will invoke the given CMake code during installation. Code is specified as a single argument inside a double-quoted string. 
Code içinde mesaj vermek için şöyle yaparız.
install(CODE "MESSAGE(\"Sample install message.\")")
Code içinde script çalıştırmak için şöyle yaparız.
install(CODE "execute_process(COMMAND my_script.sh)")
set
Bir değişkene değer atar. Böylece değişken cmake içinde kullanılabilir. Şöyle yaparız.
SET(BOOST_DIR $ENV{PATH})
Derleyici sürümü seçmek için CMAKE_CXX_FLAGS yazısına bakınız.

set_target_properties
Bazı warningleri şöyle kapatmak için şöyle yaparız.
set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "/wd4819")
Derleyici sürümü seçmek için şöyle yaparız.
add_executable(Randomshitprogram ${SOURCE_FILES})
set_target_properties(Randomshitprogram
    PROPERTIES
    CXX_STANDARD 11
    CXX_STANDARD_REQUIRED ON
)
Çıktı dosya ismini değiştirmek için şöyle yaparız.
# Adds 'd' onto artifacts - does NOT apply to executables.
# For executables, this needs to be done an exec-by-exec
# basis.
set(CMAKE_DEBUG_POSTFIX "d")

# Add postfix onto executable debug filename
set_target_properties(myapp PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
target_compile_options
Şöyle yaparız.
target_compile_options(foo PUBLIC -fno-rtti)
target_link_libraries
Target'ımız ile linklemek istediğimiz lib isimlerini yazarız. Açıklaması şöyle
target_link_libraries works on targets created with add_library and add_executable.
Şöyle yaparız. Bu komut birden fazla kere çağrılabilir.
target_link_libraries(wpcaplib.lib)
WriteCompilerDetectionHeader
Şöyle yaparız.
include(WriteCompilerDetectionHeader)

write_compiler_detection_header(
    FILE foo_compiler_detection.h
    PREFIX foo
    COMPILERS GNU
    FEATURES cxx_attribute_deprecated
)
CMake Değişkenleri
Değişlenlerin sayısı oldukça fazla. Değişkenler şöyle.

Hazır Macrolar
CMAKE_SYSTEM_NAME
CMake System Variables yazısına taşıdım.

Dizinlerle İlgili Hazır Macrolar
PROJECT_SOURCE_DIR
CMakeLists.txt dosyasının bulunduğu dizin

CMAKE_BINARY_DIR
Çıktının konulacağı dizin. Visual Studio için .sln dosyasının oluşturulacağı yer.

CMAKE_CURRENT_SOURCE_DIR
Tam ne işe yaradığını anlamadım.

Derleyiciyle İlgili Hazır Macrolar
CMAKE_ARCHIVE_OUTPUT_DIRECTORY
Statitic kütüphanenin nerede oluşturulacağını belirtir. Şöyle yaparız.
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
CMAKE_BUILD_TYPE
Şöyle yaparız.
set(CMAKE_BUILD_TYPE Release)
CMAKE_COMPILER_IS_GNUCC
Şöyle yaparız.
if (WIN32)
  if (CMAKE_COMPILER_IS_GNUCC)
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--stack,4194304 -fpermissive")
  elseif(MSVC)
    # add options for Visual C/C++ Compiler here
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /F 4194304")
  endif()
endif()
CMAKE_CXX_COMPILER
Derleyicinin ismini şöyle öğreniriz.
cmake_minimum_required (VERSION 2.8.11)

MESSAGE( STATUS "Compiler: " ${CMAKE_CXX_COMPILER} )
Çıktı olarak şunu alırız.
-- Compiler: /usr/bin/c++
Generator Expression
If/Else gibi düşünülebilir. Bir sonuç dönerler. İki noktanın solundaki değişken sağdaki değere eşitse ikinci ifade 'nin değeri dönülür. Eğer Config değişkeni Debug ise sonuç Release'dir., Config değişkeni Debug değilse boş string döner.
$<$<CONFIG:Debug>:Release>

Filtre
Visual Studio, Eclipse gibi dosya sistemi ile çalışmıyor. Kendi dosya/filtre sistemi var. Bu filtre sistemin dosya yolları ile aynı olacak şekilde üretmek için şöyle yaptım.

macro(GroupSources curdir)
   file(GLOB children RELATIVE ${PROJECT_SOURCE_DIR}/${curdir} ${PROJECT_SOURCE_DIR}/${curdir}/*)
   foreach(child ${children})
          if(IS_DIRECTORY ${PROJECT_SOURCE_DIR}/${curdir}/${child})
                  GroupSources(${curdir}/${child})
          else()
                  string(REPLACE "/" "\\" groupname ${curdir})
          # I would like to call the src root folder in a different name, only in visual studio (not mandatory requirement)
                   string(REPLACE "src" "Common" groupname ${groupname})
            source_group(${groupname} FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
          endif()
   endforeach()
endmacro()
   
# Execute the macro
GroupSources(src)



Hiç yorum yok:

Yorum Gönder