1001 * Компиляция *
Допустим, вы хотите написать простое приложение "Hello World". У вас есть 3 файла, hello.cpp
hello-writer.cpp
и hello-writer.h
, содержимое которых равно
// hello-writer.h
void WriteHello(void);
// hello-writer.cpp
#include "hello-writer.h"
#include <stdio>
void WriteHello(void){
std::cout<<"Hello World"<<std::endl;
}
// hello.cpp
#include "hello-writer.h"
int main(int argc, char ** argv){
WriteHello();
}
Файлы * .cpp преобразуются в объектные файлы с помощью g++
с помощью команд
g++ -c hello.cpp -o hello.o
g++ -c hello-writer.cpp -o hello-writer.o
Флаг -c
на данный момент пропускает связывание. Чтобы связать все модули вместе, необходимо запустить
g++ hello.o hello-writer.o -o hello
создание программы hello
. Если вам нужно связать какие-либо внешние библиотеки, вы добавляете их в эту строку, например, -lm
для математической библиотеки. Фактические файлы библиотеки будут выглядеть примерно так: libm.a
или libm.so
, при добавлении флага компоновщика вы игнорируете суффикс и часть имени файла 'lib'.
Makefile
Для автоматизации процесса сборки вы используете make-файл, который состоит из ряда правил, перечисляющих объект для создания и файлы, необходимые для его создания. Например, hello.o
зависит от hello.cpp
и hello-writer.h
, его правило
hello.o:hello.cpp hello-writer.h
g++ -c hello.cpp -o hello.o # This line must begin with a tab.
Если вы хотите прочитать руководство по сборке, в нем рассказывается, как использовать переменные и автоматические правила для упрощения вещей. Вы должны быть в состоянии просто написать
hello.o:hello.cpp hello-writer.h
и правило будет создано автоматически. Полный make-файл для примера hello:
all:hello
hello:hello.o hello-writer.o
g++ hello.o hello-writer.o -o hello
hello.o:hello.cpp hello-writer.h
g++ -c hello.cpp -o hello.o
hello-writer.o:hello-writer.cpp hello-writer.h
g++ -c hello-writer.cpp -o hello-writer.o
Помните, что строки с отступом должны начинаться с вкладок. Не то чтобы не всем правилам нужен фактический файл, цель all
просто говорит создать hello
. Обычно это первое правило в make-файле, первое создается автоматически при запуске make
.
После всех этих настроек вы сможете перейти в командную строку и запустить
$ make
$ ./hello
Hello World
Более продвинутый материал Makefile
Есть также несколько полезных переменных, которые вы можете определить в вашем make-файле, включая
- CXX: c ++ компилятор
- CXXFLAGS:
Дополнительные флаги для передачи
компилятор (например, включают в себя каталоги
с -I)
- LDFLAGS: дополнительные флаги для
перейти на компоновщик
- LDLIBS: библиотеки
по ссылке
- CC: c компилятор (также используется для
ссылка)
- CPPFLAGS: флаги препроцессора
Определить переменные с помощью =
, добавить к переменным с помощью +=
.
Правило по умолчанию для преобразования файла .cpp в файл .o:
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@
, где $<
- первая зависимость, а $@
- выходной файл. Переменные расширяются, заключая их в $()
, это правило будет выполняться с шаблоном hello.o:hello.cpp
Аналогично, правило компоновщика по умолчанию -
$(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS)
, где $^
- все предпосылки. Это правило будет выполняться с шаблоном hello:hello.o hello-writer.o
. Обратите внимание, что здесь используется компилятор c, если вы не хотите переопределять это правило и используете c ++, добавьте библиотеку -lstdc++
в LDLIBS
со строкой
LDLIBS+=-lstdc++
в make-файле.
Наконец, если вы не перечислите зависимости файла .o
, make может найти их сам, поэтому минимальный make-файл может быть
LDFLAGS=-lstdc++
all:hello
hello:hello.o hello-writer.o
Обратите внимание, что при этом игнорируется зависимость двух файлов от hello-writer.h
, поэтому, если заголовок будет изменен, программа не будет перестроена. Если вам интересно, проверьте флаг -MD
в документации gcc, чтобы узнать, как автоматически генерировать эту зависимость.
Окончательный make-файл
Разумный финальный make-файл будет
// Makefile
CC=gcc
CXX=g++
CXXFLAGS+=-Wall -Wextra -Werror
CXXFLAGS+=-Ipath/to/headers
LDLIBS+=-lstdc++ # You could instead use CC = $(CXX) for the same effect
# (watch out for c code though!)
all:hello # default target
hello:hello.o hello-world.o # linker
hello.o:hello.cpp hello-world.h # compile a module
hello-world.o:hello-world.cpp hello-world.h # compile another module
$(CXX) $(CXXFLAGS) -c $< -o $@ # command to run (same as the default rule)
# expands to g++ -Wall ... -c hello-world.cpp -o hello-world.o