Cmake vs make образцы кодов?

120

Мне было интересно, есть ли какой-нибудь пример кода для Makefiles ( make) и CMakeLists.txt( cmake), которые оба делают одно и то же (единственная разница в том, что один написан, makeа другой - cmake).

Я попытался найти cmake vs make, но так и не нашел сравнения кода. Было бы действительно полезно понять различия, даже если бы это был простой случай.

JLo
источник
20
+1 Это хороший вопрос; когда я только начинал, cmakeя тоже этого хотел. Но я сомневаюсь, что вы его найдете, потому что возможности просто не очень хорошо соотносятся друг с другом. Если вы попытаетесь вести cmakeсебя так make, как будто вы серьезно сведете себя с ума. Лучше всего начать с нуля. Вещи, которые являются тривиальными make, довольно сложны cmake, и наоборот.
Эрнест Фридман-Хилл,
1
@ ErnestFriedman-Hill, у вас есть подробности по этому поводу? Так makeи cmakeнастолько различны, что их следует рассматривать скорее как дополнительные, а не как конкурирующие инструменты?
Ehtesh Choudhury
3
@Shurane - cmake сам ничего не строит; он создает файлы Makefile (и другие подобные сценарии сборки), которые вы затем запускаете. Поэтому всякий раз, когда вы пишете файлы cmake, вы должны подумать, должна ли команда применяться во время генерации или во время сборки. Некоторые действия - например, копирование набора файлов с подстановочными знаками во время сборки - довольно сложны по сравнению с " cp *.x $(OUTDIR)", которые вы бы написали в Makefile. Возможно, самое неприятное для меня то, что сгенерированные файлы Makefile по замыслу совершенно непереносимы и негибки (продолжение)
Эрнест Фридман-Хилл
1
(продолжение) Вы даже не можете переместить исходный каталог на тот же компьютер без повторного запуска cmake для регенерации Makefile! Таким образом, выбор стоит не между cmake и make, а между написанием переносимых файлов Makefile самостоятельно или использованием cmake для создания непереносимых файлов на каждой машине сборки (и, учитывая, что вы можете использовать Cygwin или mingw в Windows, я обычно считаю, что первое проще. )
Эрнест Фридман-Хилл
1
хороший вопрос, но на него нет конкретного ответа, потому что оба инструмента пытаются решить разные проблемы. cmake берет информацию о том, как создавать программы, генерирует make-файлы, которые собирают программу. Следовательно, cmake - это язык с абстрактными правилами сборки, а gnu make - это средство разрешения зависимостей, которое выполняет программы на направленном ациклическом обходе графа.
Alex

Ответы:

119

Следующий 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>каталог сборки, либо запустив какой-либо клиент с графическим интерфейсом). Это создает Makefile или что-то подобное, в зависимости от выбранной вами системы сборки (например, make в Unix или VC ++ или MinGW + Msys в Windows). Систему сборки можно передать CMake в качестве параметра; однако CMake делает разумный выбор по умолчанию в зависимости от конфигурации вашей системы. Во-вторых, вы выполняете фактическую сборку в выбранной системе сборки.

Исходные коды и инструкции по сборке доступны по адресу https://github.com/rhoelzel/make_cmake .

Роберто
источник
3
Разве Makefile не слишком сложен? При использовании CPPFLAGSвместо INCDIRможно было бы использовать встроенные правила, и явный вызов компилятора был бы излишним. Точно так же для обработки ar встроенные правила также могут покрыть это. Кроме того, зачем устанавливать CPPи CCявно? Для них уже установлены хорошие значения make, они являются предопределенными переменными. makeтакже распознает, какой компилятор использовать для какого типа источника, встроенных правил много.
Christian Hujer 07
1
И многим из этих переменных следует назначать :=вместо =.
Christian Hujer 07
1
Глядя на описание, cmakeболее сопоставимо с automakeчем make.
ivan_pozdeev
Предоставляемый Makefile может быть уменьшен до 3/4 строк. Вы ДОЛЖНЫ указать INCLUDESвместо INCDIR. Вам не нужны правила% .o:%. C.
Шува
7

Возьмите какое-нибудь программное обеспечение, которое использует CMake в качестве своей системы сборки (в качестве примера можно выбрать множество проектов с открытым исходным кодом). Получите исходный код и настройте его с помощью CMake. Прочтите полученные make-файлы и наслаждайтесь.

Следует иметь в виду, что эти инструменты не соответствуют друг другу. Наиболее очевидное различие состоит в том, что CMake сканирует зависимости между разными файлами (например, заголовком C и исходными файлами), тогда как make оставляет это на усмотрение авторов make-файлов.

Тадеуш А. Кадлубовски
источник
4

Если этот вопрос касается образца Makefileвывода CMakeList.txtфайла, проверьте исходники cmake-backend и сгенерируйте один из них 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) против правил создания

В используются вместо . В дополнение к -подобной функции обеспечьте цепочку. Мой минимализм будет выглядеть следующим образом,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чтобы детали, определенные в одном файле. Таким образом можно уменьшить размер make-файла, как я показал ранее.

Внутренние переменные в CMakeиMake

Теперь, когда CMakeмы немного продвинулись, мы можем установить флаг компилятора следующим образом:

set(CMAKE_C_FLAGS "-Wall")

Пожалуйста, узнайте больше о CMakeпеременных по умолчанию в CMakeCache.txtфайле. Приведенный CMakeвыше код будет эквивалентен Makeприведенному ниже коду,

CFLAGS = -Wall

Обратите внимание, что CFLAGSэто внутренняя переменная в Make, точно так же, CMAKE_C_FLAGSэто внутренняя переменная в CMake.

добавление включения и пути к библиотеке в CMake

Мы можем сделать это с cmakeпомощью functions.

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

Против добавления include и пути к библиотеке в Make

Мы можем добавить include и библиотеки, добавив такие строки, как следующие:

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

Обратите внимание, что эти строки выше могут быть созданы с помощью инструментов auto-gen или pkg-config. (хотя Makefile не зависит от инструментов автоконфигурации)

CMake настроить / настроить

Обычно можно сгенерировать некоторый config.hфайл, как и auto-configинструменты, с помощью configure_fileфункции. Можно сделать больше трюков, написав собственные функции. И, наконец, мы можем выбрать следующую конфигурацию:

cmake --build . --config "Release"

С помощью optionфункции можно добавить некоторые настраиваемые параметры .

Настройка / настройка Makefile

Если каким-то образом нам нужно скомпилировать его с каким-либо флагом отладки, мы можем вызвать makeподобное,

make CXXFLAGS=NDEBUG

Я думаю , что внутренние переменные, Makefile-rulesи CMake-functionsявляются хорошим началом для сравнения, удачи с большим количеством рытья.

Шува
источник