Cmake vs зробити зразкові коди?


118

Мені було цікаво, чи існує зразок коду для Makefiles ( make) та CMakeLists.txt( cmake), що обидва роблять те саме (різниця лише в тому, що один записаний, makeа інший в cmake).

Я намагався шукати "cmake vs make", але ніколи не знайшов порівняння коду. Було б дуже корисно зрозуміти відмінності, навіть якщо тільки для простого випадку.


20
+1 Це гарне запитання; коли я починав з цього, cmakeя хотів і цього. Але я сумніваюсь, що ви знайдете це, оскільки можливості просто не відповідають тому, що добре. Якщо ви спробуєте змусити cmakeсебе так діяти make, ви серйозно змусите себе. Краще всього починати з нуля. Речі, які є банальними make, досить задіяні cmake, і навпаки.
Ернест Фрідман-Хілл

1
@ ErnestFriedman-Hill Ви маєте більше деталей щодо цього? Так makeі cmakeнастільки виразні, що їх слід розглядати як доповнення, а не змагальні інструменти?
Ehtesh Choudhury

2
@Shurane - cmake нічого не будує сам; він створює Makefiles (та інші подібні сценарії збірки), які ви потім запускаєте. Тому щоразу, коли ви пишете файли cmake, ви повинні думати, чи повинна застосовуватися команда під час генерації чи під час збирання. Деякі дії - наприклад, копіювати набір файлів із заздалегідь поміченим файлом під час збирання - є досить складними, порівняно з " cp *.x $(OUTDIR)", які ви писали б у Makefile. Мабуть, найприємніша частина для мене - це те, що створені Makefiles за конструкцією є абсолютно нерепортажними та негнучкими (продовження)
Ернест Фрідман-Хілл

1
(продовження) Ви навіть не можете перемістити вихідний каталог на одній машині без повторного запуску cmake, щоб відновити Makefile! Тож вибір не між cmake і make, а скоріше між написанням портативних Makefiles самостійно, або використанням cmake для створення неподільних на кожній машині складання (і враховуючи, що ви можете використовувати Cygwin або mingw в Windows, я вважаю, що колишній простіше. )
Ернест Фрідман-Хілл

1
приємне запитання, але конкретної відповіді немає, оскільки обидва інструменти намагаються вирішити іншу проблему. cmake приймає інформацію про те, як створювати програми, генерує файли, які будують програму. Отже, cmake - це мова з абстрактними правилами побудови, а gnu make - це залежність, яка виконує програми, спрямовані на ациклічний графічний траверс графіка.
Олексій

Відповіді:


118

Наступний Makefile створює виконуваний файл, названий progз джерел prog1.c, prog2.c, prog3.c and main.c. progпов'язані проти, libmystatlib.a і libmydynlib.soобидва вони також побудовані з джерела. Крім того, progвикористовує бібліотеку libstuff.aв stuff/libта її заголовок у stuff/include. Makefile за замовчуванням створює ціль випуску, але пропонує також ціль налагодження:

#Makefile    
CC = gcc
CPP = g++
RANLIB = ar rcs
RELEASE = -c -O3 
DEBUG = -c -g -D_DEBUG
INCDIR = -I./stuff/include
LIBDIR = -L./stuff/lib -L.
LIBS = -lstuff -lmystatlib -lmydynlib
CFLAGS = $(RELEASE)

PROGOBJS = prog1.o prog2.o prog3.o

prog: main.o $(PROGOBJS) mystatlib mydynlib
    $(CC) main.o $(PROGOBJS) $(LIBDIR) $(LIBS) -o prog 
debug: CFLAGS=$(DEBUG)
debug: prog

mystatlib: mystatlib.o
    $(RANLIB) libmystatlib.a mystatlib.o
mydynlib: mydynlib.o
    $(CPP) -shared mydynlib.o -o libmydynlib.so

%.o: %.c
    $(CC) $(CFLAGS) $(INCDIR) $< -o $@ 
%.o: %.cpp
    $(CPP) $(CFLAGS) $(INCDIR) -fPIC  $< -o $@ 

Ось це CMakeLists.txtробить (майже) точно так само, з деякими коментарями, щоб підкреслити схожість з Makefile:

#CMakeLists.txt     
cmake_minimum_required(VERSION 2.8)                    # stuff not directly
project(example)                                       # related to building

include_directories(${CMAKE_SOURCE_DIR}/stuff/include) # -I flags for compiler
link_directories(${CMAKE_SOURCE_DIR}/stuff/lib)        # -L flags for linker

set(PROGSRC prog1.c prog2.c prog3.c)                   # define variable 

add_executable(prog main.c ${PROGSRC})                 # define executable target prog, specify sources
target_link_libraries(prog mystatlib mydynlib stuff)   # -l flags for linking prog target

add_library(mystatlib STATIC mystatlib.c)              # define static library target mystatlib, specify sources

add_library(mydynlib SHARED mydynlib.cpp)              # define shared library target mydynlib, specify sources
#extra flags for linking mydynlib
set_target_properties(mydynlib PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 
#alternatively:
#set_target_properties(mydynlib PROPERTIES COMPILE_FLAGS "-fPIC")

У цьому простому прикладі найбільш важливі відмінності:

  • CMake розпізнає, які компілятори використовувати для якого типу джерела. Крім того, він викликає правильну послідовність команд для кожного типу цілі. Таким чином, не існує явна специфікація команд , як $(CC) ..., $(RANLIB) ...і так далі.

  • Усі звичайні прапорці компілятора / лінкера, що стосуються включення файлів заголовків, бібліотек тощо, замінюються незалежними від платформи / складають системні незалежні команди.

  • Налагодження прапори включені або встановивши змінну CMAKE_BUILD_TYPEв «Debug» або шляхом передачі його в CMake при виклику програми: cmake -DCMAKE_BUILD_TYPE:STRING=Debug.

  • CMake пропонує також платформу незалежного включення прапора '-fPIC' (через POSITION_INDEPENDENT_CODEвласність) та багатьох інших. Тим не менш, більш незрозумілі налаштування можуть бути реалізовані вручну в CMake так само, як і в Makefile (за допомогою COMPILE_FLAGS та подібних властивостей). Звичайно, CMake дійсно починає світитися, коли сторонні бібліотеки (наприклад, OpenGL) включаються портативно.

  • Процес збирання має один крок, якщо ви використовуєте Makefile, а саме вводите makeкомандний рядок. Для CMake є два етапи: По-перше, вам потрібно налаштувати середовище збирання (або ввівши cmake <source_dir>у каталог збірки, або запустивши якийсь клієнт GUI). Це створює Makefile або щось еквівалентне, залежно від обраної системи збирання (наприклад, зробити на Unixes або VC ++ або MinGW + Msys в Windows). Система збірки може бути передана CMake як параметр; однак CMake робить розумний вибір за замовчуванням залежно від конфігурації вашої системи. По-друге, ви виконуєте фактичну збірку у вибраній системі збірки.

Джерела та інструкції зі зборки доступні на веб-сторінці https://github.com/rhoelzel/make_cmake .


3
Хіба Makefile не надто складний? Якщо CPPFLAGSзамість INCDIRодного можна було використовувати вбудовані правила, явне виклик компілятора було б зайвим. Аналогічно для обробки ар, вбудовані правила також можуть охоплювати це. Крім того, навіщо встановлювати CPPі CCпрямо? Вони вже встановлені на хороші значення за допомогою makeпопередньо визначених змінних. makeтакож визнає, який компілятор використовувати для якого типу джерела, вбудованих правил багато.
Крістіан Худжер

1
І багато з цих змінних слід присвоювати :=замість =.
Крістіан Худжер

1
Дивлячись на опис, cmakeпорівнянніше automakeніж make.
ivan_pozdeev

Наданий Makefile може бути скорочений до 3/4 рядків. Ви повинні Вказувати INCLUDESзамість INCDIR. Вам не потрібні правила% .o:%. C.
шува

6

Візьміть деяке програмне забезпечення, яке використовує CMake як свою збірну систему (є безліч проектів з відкритим кодом, які можна вибрати як приклад). Отримайте вихідний код і налаштуйте його за допомогою CMake. Читайте отримані файли та насолоджуйтесь.

Потрібно пам’ятати, що ці інструменти не відображають один на один. Найбільш очевидною відмінністю є те, що CMake сканує залежність між різними файлами (наприклад, заголовком C та вихідними файлами), тоді як робить це авторами makefile.


4

Якщо це питання стосується зразкового Makefileвиводу CMakeList.txtфайлу, то, будь ласка, перевірте джерела cmake-backkend та генеруйте одне такеMakefile . Якщо це не додавання до відповіді @Roberto, я намагаюся спростити це, приховавши деталі.

Функція CMake

Хоча Makeце гнучкий інструмент для правил та рецептів,CMake це шар абстракції, який також додає функцію конфігурації.

Моя рівнина CMakeLists.txtбуде виглядати наступним чином,

cmake_minimum_required(VERSION 2.8)
project(example)
file(GLOB testapp_SOURCES *.cc)
add_executable(testapp ${testapp_SOURCES})

Зауважте, що CMakeприховувати howзбірку можна. Ми лише вказали whatвхід і вихід.

CMakeLists.txtМістить список функцій-викликів, які визначені cmake.

(Функція CMake) Vs Складіть правила

В використовуються замість . Окрім -подібної функції, надайте прив’язування. Мій мінімалістичний буде виглядати наступним чином,Makefilerules and recipesfunctionsfunctionrules and recipesMakefile

-include "executable.mk"
TARGETS=testapp.bin
all:${TARGETS}

Хоча executable.mkзаповіт буде виглядати наступним чином,

SOURCES=$(wildcard *.cpp)
OBJECTS=$(SOURCES:.cpp=.o)
DEPS=$(SOURCES:.cpp=.d)

%.bin:$(OBJECTS)
    $(CC) $(CFLAGS) -o $@ $^ $(LFLAGS) $(LIBS)

.PHONY: all clean

clean:
    $(RM) $(OBJECTS) $(DEPS) $(TARGETS)

-include $(DEPS)

Починаючи з нуля, я розпочну з Makefileнаступного,

all: testapp.bin

testapp.bin:sourcea.o sourcb.o
    $(CC) $(CFLAGS) -o $@ $^ $(LFLAGS) $(LIBS)

.PHONY: all clean

clean:
    $(RM) $(OBJECTS) testapp.bin

Я взяв цей фрагмент звідси і змінив його. Зауважте, що до цього файлу додаються деякі неявні правила, які можна знайти в документації makefile. Тут також мають значення деякі неявні змінні.

Зверніть увагу, що Makefileзабезпечує деталізацію з recipeзазначенням howскладання може бути зроблено. Можна записати, executable.mkщоб зберегти дані, визначені в одному файлі. Таким чином, makefile можна зменшити, як я показав раніше.

Внутрішні змінні в CMakeіMake

Тепер трохи просунувшись, CMakeми можемо встановити прапор компілятора на зразок наступного,

set(CMAKE_C_FLAGS "-Wall")

Дізнайтеся більше про CMakeзмінні за замовчуванням у CMakeCache.txtфайлі. CMakeВище код буде еквівалентний Makeкоду нижче,

CFLAGS = -Wall

Зауважте, що CFLAGSвнутрішня змінна в Make, таким же чином, CMAKE_C_FLAGSє внутрішньою змінною вCMake .

додавання включають і шлях до бібліотеки в CMake

Ми можемо це зробити за cmakeдопомогою функцій.

target_include_directories(testapp PRIVATE "myincludes")
list(APPEND testapp_LIBRARIES
    mytest mylibrarypath
)
target_link_libraries(testapp ${testapp_LIBRARIES})

Додавання Vs включає і бібліотечний шлях у Make

Ми можемо додавати включення та бібліотеки, додаючи рядки, як описано нижче,

INCLUDES += -Imyincludes
LIBS += -Lmylibrarypath -lmytest

Зверніть увагу, що рядки вище можуть бути створені за допомогою інструментів автоматичного генерування або pkg-config. (хоча Makefile не залежить від інструментів автоматичного налаштування)

CMake configure / tweek

Зазвичай за допомогою функції можна генерувати якийсь config.hфайл, як і auto-configінструменти configure_file. Можна зробити більше трюків, написавши спеціальні функції. І, нарешті, ми можемо вибрати конфігурацію, як описано нижче,

cmake --build . --config "Release"

За допомогою optionфункції можна додати деякий параметр, який можна настроїти .

Налаштування / налаштування Makefile

Якщо нам якось потрібно скомпілювати його з деяким прапором налагодження, ми можемо викликати makeподібне,

make CXXFLAGS=NDEBUG

Я думаю, що внутрішні змінні, Makefile-rulesі CMake-functionsє гарним початком для порівняння, удачі з більшою кількістю копання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.