Насколько я понимаю, это правило должно принимать все объектные файлы и создавать исполняемый файл с тем же именем, что и объектный файл, но я не мог заставить его работать! Есть ли у кого-нибудь подсказка, как этого добиться?
c++ makefile rules targetsКак зависимости работают на gnu Makefile ? Я хочу создать файл Makefile, который: — придется применить некоторые патчи (в нашем, например, применять main.patch на main.c) — создайте программу под названием toto из исправленного файла main.c my_patch=./main.patch all: toto patch: $(my_patch) echo…
я создал Makefile, который я бы изменил так, чтобы он генерировал более одной цели, когда я запускаю make . $(LOADLIBES) $(LDLIBS) -o $@
таким образом, вы можете использовать эти переменные для выбора компилятора, указывающего флаги для препроцессора, компилятора и компоновщика. Например, вы можете изменить CXX
, чтобы использовать компилятор для неправильного языка , и исправить ущерб, добавив LDFLAGS=-lstdc++
, как это делает ваш makefile, если вы действительно хотите.
Поделиться Mike Seymour 12 декабря 2014 в 11:11
0
Вот решение:
В приведенных выше примерах я не использую переменную $(LDLIBS), которая используется встроенным правилом по умолчанию. Если я изменю свой Makefile на использование $(LDLIBS) вместо $(LDFLAGS), все будет в порядке!
Решение #1: (встроенное правило)
CC=gcc
CFLAGS=-g -fopenmp
LDFLAGS=
LDLIBS = -lstdc++ -lgomp
ECHO = echo
SILENT = @
MODULES = example1 example2 example3
all: $(MODULES)
clean:
$(SILENT) $(ECHO) "--- Removing object files and binaries ---"
$(SILENT) rm -f *. $(LDLIBS) -o $@
clean:
$(SILENT) $(ECHO) "--- Removing object files and binaries ---"
$(SILENT) rm -f *.o
$(SILENT) rm -f $(MODULES)
.PHONY: clean
Поделиться Marcel Stüttgen 16 декабря 2014 в 09:59
В рецепте для цели я хочу сгенерировать скрипт bash, который обрабатывает аргументы командной строки …, однако экранирование Makefile ускользает от меня цель: deps Эхо ./a.out \$@\ > wrapper.a.out…
Я немного использовал rake (a Ruby make program), и у него есть возможность получить список всех доступных целей, например > rake —tasks rake db:charset # retrieve the charset for your data……
Есть ли универсальный makefile, который я могу использовать для создания простого проекта c++? на windows? я изменил рабочий файл Wii makefile на win32, но не смог построить его должным образом…
Как зависимости работают на gnu Makefile ? Я хочу создать файл Makefile, который: — придется применить некоторые патчи (в нашем, например, применять main.patch на main.c) — создайте программу под…
я создал Makefile, который я бы изменил так, чтобы он генерировал более одной цели, когда я запускаю make . В своей программе я использую self predetended macros (например , TIME , REG и _DEBUG ), и…
Я пытаюсь отредактировать файл makefile, я уже создал свой собственный, но я изо всех сил пытаюсь понять этот очень минимальный пример, который явно использует соглашения, о которых я не знаю. Я…
Из документов : Директива include предписывает make приостановить чтение текущего make-файл и прочитайте один или несколько других make-файлов, прежде чем продолжить. Директива представляет собой…
Поэтому в рамках нескольких инструментов, которые я делаю в C++, я хотел иметь возможность тестировать каждый инструмент индивидуально. Существует несколько инструментов с несколькими тестовыми…
У меня есть GNU makefile, который компилирует набор исходных кодов в моей системе, и я хочу передать исходный код другому человеку (другой системе), так будет ли тот же самый GNU makefile…
Возникла необходимость написать на С++ небольшую программу (500-1К строк), а с IDE я как-то не дружу (программируя на python и java обхожусь sublime’ом), да и хотелось узнать, как компилировать программы из консоли. Поэтому я написал «классовый» HelloWorld и начал читать этот мануал. Проблемы возникли при написании универсального makefile’a.
«Захардкоженный» makefile выглядит так (всё лежит в одной папке):
all: Greetings
Greetings: main_greetings.o greetings_printer.o
g++ -o Greetings main_greetings.o greetings_printer.o
greetings_printer.o: GreetingsPrinter.cpp
g++ -c -o greetings_printer.o GreetingsPrinter.cpp
main_greetings.o: Greetings.cpp
g++ -c -o main_greetings.o Greetings.cpp
и команда
make -f makefile.makefile
делает всё, что нужно: программа компилируется и работает.
Но вот попытка написать универсальный makefile оборачивается провалом. Сам makefile:
TARGET = $( shell basename 'pwd' )
SOURCES = $( wildcard *.cpp )
OBJECTS = $( SOURCES:%.cpp=%.o )
all: $(TAGRET)
$(OBJECTS): $(SOURCES)
$(TAGRET): $(OBJECTS)
$(CXX) -o $(TAGRET) $(LDFLAGS) $(OGJECTS) $(LOADLIBES) $(LDLIBS)
clean:
$(RM) $(OBJECTS) $(TAGRET)
.PHONY: all clean
а предыдущий вызов из консоли выдаёт такой результат:
make: Nothing to be done for `all'.
В чём ошибка?
Попробовал вот так:
make Greetings
Вывод:
g++ Greetings.cpp -o Greetings /tmp/ccGdTOxR.o: In function `main': Greetings.cpp:(.text+0x1d): undefined reference to `MyGreetingsPrinter::MyGreetingsPrinter()' Greetings.cpp:(.text+0x29): undefined reference to `MyGreetingsPrinter::PrintGreetings()' collect2: ld returned 1 exit status make: *** [Greetings] Error 1
Хотя с первой версией makefile программа работала без ошибок.
правило
$(OBJECTS): $(SOURCES)
$(CC) $(CFLAGS) $< -o $@
не совсем корректно. Данное правило будет раскрыто как 2 правила
build/main.o: src/main.cpp src/file.cpp
g++ -c -Wall src/main.cpp -o build/main.o
build/file.o: src/main.cpp src/file.cpp
g++ -c -Wall src/main.cpp -o build/file.o
Физика процесса такова:
$(OBJECTS): раскрываеться как 2 объектника, и Make система генерит по 1 правилу (таргету) для каждого из них. Тут все верно и ожидаемо.
$< подставляет первый элемент из списка после двоеточия. Вот здесь и есть основная проблема, изза которой оба таргета компилируют один и тот же файл.
(то как Gnu Make раскрывает таргеты можно увидеть запустив ‘make -np all > logfile’)
Соответственно, чтобы исправить ситуацию нужно каждому таргету подставлять правильный исходник. Чтобы автоматизировать процесс советую применить трюк с правилом
%c: %o
...
Ниже — пример билд системы, которая сама подхватывает все исходники в заданых директориях.
Дервв файлов:
. |-- include | `-- func.h |-- Makefile |-- src | `-- func.c `-- src2 `-- prog.c
Makefile:
#Name of outpu binary (exe) file;
PROGRAM_NAME := prog
# project dirs
export PROJECT_DIR := $(shell pwd)
export SRC_DIRS := $(PROJECT_DIR)/src
export SRC_DIRS += $(PROJECT_DIR)/src2
export INCLUDE_DIR := $(PROJECT_DIR)/include
export BUILD_DIR := $(PROJECT_DIR)/build
export OBJ_DIR := $(BUILD_DIR)/obj
export TARGET_DIR := $(BUILD_DIR)/target
# this meens that "checkbuilddirs" is not a file but rule to run
.PHONY: checkbuilddirs
#list of source files (with whitespace between them)
SRC_FILES := $(foreach dirname, $(SRC_DIRS), $(wildcard $(dirname)/*.c))
#Object files
OBJ_FILES := $(foreach filename, $(notdir $(SRC_FILES)), $(OBJ_DIR)/$(filename:.c=.o))
# dependence dirs. VPATH is defined by gnu Make and used to look for any files if we use %
# It is like -I include dirs for compiller
VPATH:=$(sort $(SRC_DIRS) $(foreach srcfile,$(SRC_FILES),$(dir $(srcfile))))
# Include flags
LOCAL_INCLUDES:=$(foreach dirs, $(INCLUDE_DIR), -I$(dirs))
PROGRAM_FULL_NAME := $(TARGET_DIR)/$(PROGRAM_NAME)
# list of lib-flags for compiler. For example for math.h use -lm
#LIB_FLAGS=-lm
CC:=gcc
CFLAGS:=-Wall $(LIB_FLAGS) $(LOCAL_INCLUDES)
# rule to build application
all: checkbuilddirs $(PROGRAM_FULL_NAME)
VERBOSE ?= false
ifeq ($(VERBOSE),true)
QUIET :=
else
QUIET := @
endif
#build executable file
$(PROGRAM_FULL_NAME): $(OBJ_FILES)
@echo "Build program"
$(QUIET)$(CC) $(CFLAGS) -o $@ $^
# build all object file
$(OBJ_DIR)/%.o: %.c
@echo "Compile $(notdir $<)"
$(QUIET)$(CC) -c $(CFLAGS) $< -o $@
#clean all
clean:
$(QUIET)rm -f $(OBJ_FILES) $(PROGRAM_FULL_NAME)
$(QUIET)rm -f $(BUILD_DIR) -r
checkbuilddirs: | $(BUILD_DIR) $(OBJ_DIR) $(TARGET_DIR)
$(BUILD_DIR):
$(QUIET)mkdir -p $@
$(OBJ_DIR):
$(QUIET)mkdir -p $@
$(TARGET_DIR):
$(QUIET)mkdir -p $@
Обратите внимание на сл. трюки:
команда $(wildcard $(dirname)/*.c) сама найдет все файлы *.с в указаных директориях
$(OBJ_DIR)/%.o: %.c — трактуется билд системой как универсальный таргет, который система применит для всех объектников. Обратите внимание, что исходный файл тут указан без указания папки.
переменная VPATH — как было сказано выше, все исходники в dependency указаны без папок. VPATH — специальная переменная, используеться системой Make как список папок в которых можно искать исходники. Очень похоже на PATH, только для поиска исходников.
PS. пример проверен
Что делаю не так?
--force
во всех командах SVN рекомендую забыть наглухоПока src не часть репозитория (? src
), SVN ничего и никак не может сделать с его содержимым (его просто нет), ну и все родительские svn:ignore
|svn:global-ignores
на /src просто не работают
Варианты решения (от более простого к более геморройному)
svn add src
(все еще пустой) /src
), после этого перенести все файлы на законное место в srcПолучается примерно так
>dir /B /S
z:\WC2\src
z:\WC2\Makefile.am
z:\WC2\configure.in
>svn pl -v
Properties on '.':
svn:global-ignores
Makefile.am
>svn st --no-ignore
M .
I Makefile.am
? configure.in
? src
(единственный M
из-за propset)
>svn add src
A src
В /src
как уже в части репо наследуется игнор-лист
src>svn pl --show-inherited-props
Inherited properties on '.',
from 'Z:\WC2':
svn:global-ignores
и после копирования в него отложенных до того файлов
>svn st --no-ignore
M .
I Makefile.am
? configure.in
A src
I src\Makefile.am
? src\main.c
Если пустое дерево не получается/лениво/есть возможность наколбасить, то процесс практически такой же, с единственным отличием — при svn add src
надо помнить, что add рекурсивен до упора, и чтобы он не добавил лишнего, добавляем только /src, без содержимого (после добавления игнор-лист подхватится и будет легче) — это ключ --depth 'empty'
Универсальный, но неудобный для работы руками вариант. У svn add есть ключик --targets
, параметр которого — файл со списком всех дополнительных файлов (и вообще объектов), которые нужно добавить в дополнение к поименованным в командной строке.
Из dir|ls
z:\WC2\src
z:\WC2\Makefile.am
z:\WC2\configure.in
z:\WC2\.svn\pristine
z:\WC2\.svn\tmp
z:\WC2\.svn\wc.db
z:\WC2\.svn\entries
z:\WC2\.svn\format
z:\WC2\src\Makefile.am
z:\WC2\src\main.c
достаточно легко получить (убиранием ненужного)
configure.in
src\main.c
Руководство по современному Make
Прежде чем пилить проект, наточи пилу!
– Что говорит кошка, когда хочет кушать?
– Мяу!
– Что говорит собака, когда чует опасность?
– Гав-гав!
– А что говорит Вова когда хочет задеплоить проект?
– ansible-playbook -i inventory/production --tags "deploy" app-server.yml -vvv --become-user=app --extra-vars=extra.txt --vault-password-file="~/.ansible/vault.txt"
Такие штуки незаметно отъедают ваше рабочее время и мозготопливо
12 минут в день на рутину == 4 часа в месяц == ~1.5 рабочих недели в год
Make позволяет нарулить себе библиотеку команд-шорткатов, которые будут отражать семантику происходящего, а не реализацию:
make deploy
, make logs
, make feature resubscription
Makefile хранится в основном репозитории вместе с кодом и становится живой документацией по частоиспользуемым при разработке командам.
– О, камон, Make — это же что-то очень древнее! Где ты это выкопал вообще?
– Я помню два года назад что-то собирал из сорцов мэйком. Разве он годится для чего-то еще?
– Слушай, я же не на сях пишу чтобы что-то там билдить. У меня уже есть npm/rake/maven, какой мне еще мэйк?
Примерно так я думал, пока не разобрался в вопросе.
По факту Make – это такой универсальный клей между кучей технологий используемых в современной разработке. У него минимальный оверхед по сравнению со специфичными для языков инструментами.
Голосование в твиттере доказывает что с вероятностью в 75% вы не используете Makefile в своих проектах:
Если это так, значит что у вас сейчас есть возможность потратив пару часов, сэкономить себе в будущем гораздо больше времени.
Сейчас для меня Make стоит в одном ряду с Ansible, Docker и GitLab CI.
Это добротный универсальный, по-хорошему хипстерский инструмент для упорядочивания хаоса в рабочих скриптах на проекте.
Make всем хорош, но его официальная документация чересчур подробна, и, видимо, рассчитана на сисадминов-сишников, думающих на bash. Пробиться через неё без специальной подготовки нереально – слишком много специфики и деталей далеких от нужд современного разраба.
Поэтому я запилил мини-руководство по полезным для современного разраба фишкам Make. Получилось так:
Официальная документация:
Выжимка актуальной годноты:
500 строкНа самом деле вам не нужно читать и их 🙂
Как же так?
Что же делать?
1. Чтобы понять основную идею использования Make и базовые правила, посмотрите ролик от Хекслета ▶️ (8.5 минут на полуторной скорости).
2. Если решили применить Make на практике, то вам пригодится дока по основным фишкам и особенностям настройки Makefile.
3. Если в стремлении навести порядок вы решили идти до конца, то для вас есть расширенная версия с примером построения цельного workflow для dev/staging/production-окружений.
Руководство по современному Make
1. Making your library of shortcuts
2. Overcoming Make weirdness
3. Multiple commands at once
4. Subcommands
5. Aliases
6. Multiline commands
7. Suppressing output
8. Conditional execution
9. Passing arguments
10. Advanced scripting
11. Putting things in order
12. Naming conventions
13. Full workflow automation
14. Guiding principles
← Это еще дописывается
Всё выглядит слишком просто?!
Жмите на специальную ссылку для самых умных 😉
💌Сорян!
Полная версия еще не готова.
Подпишитесь, и пришлю вам письмо, как только так сразу:
Установить необязательные продукты — File Magic (Solvusoft) | EULA | Privacy Policy | Terms | Uninstall
Если на вашем компьютере не установлена программа, совместимая с файлами MAKEFILE, вы не сможете ее открыть. Посмотрите, есть ли у вас одна из наиболее распространенных программ, связанных с файлами MAKEFILE, перечисленными ниже.
Если вы не можете открыть файлы MAKEFILE, попробуйте выяснить тип файла. Это поможет вам найти нужную программу для ее открытия. Обычно файлы MAKEFILE считаются Необычные файлы. Однако вы можете искать тип файла, чтобы быть уверенным. Начните с правого щелчка на значке файла и нажмите «Свойства» («Дополнительная информация», если вы на Mac). Затем найдите тип файла в разделе «Тип файла» («Вид» на Mac).
Когда вы не можете открыть файлы MAKEFILE, разработчик программного обеспечения может помочь. Разработчики для упомянутых выше программ выглядят следующим образом:
Программного обеспечения | разработчик |
---|---|
Makefile | Unknown |
Попробуйте связаться с одним из этих разработчиков, чтобы узнать, как открыть файл MAKEFILE.
Универсальный просмотрщик файлов — это путь, когда у вас есть файлы MAKEFILE, которые не могут быть открыты какой-либо другой программой. Установите универсальный просмотрщик файлов, например File Magic (Загрузить), и посмотрите, откроет ли ваш файл MAKEFILE. Помните, что если ваш файл несовместим, универсальный просмотрщик файлов откроет его только в двоичном формате.
Загрузить Просмотр файлов Универсальный (File Magic)
Установить необязательные продукты — File Magic (Solvusoft) | EULA | Privacy Policy | Terms | Uninstall
В жизни многих разработчиков найдётся история про первый рабочий день с новым проектом. После клонирования основного репозитория проекта наступает этап, когда приходится вводить множество команд с определёнными флагами и в заданной последовательности. Без описания команд, в большинстве случаев, невозможно понять что происходит, например:
# Bash
touch ~/.bash_history
ufw allow 3035/tcp || echo 'cant configure ufw'
ufw allow http || echo 'cant configure ufw'
docker run \
-v /root/:/root/ \
-v /etc:/etc \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /var/tmp:/var/tmp \
-v /tmp:/tmp \
-v $PWD:/app \
--network host \
-w /app \
--env-file .env \
ansible ansible-playbook ansible/development.yml -i ansible/development --limit=localhost -vv
grep -qxF 'fs.inotify.max_user_watches=524288' /etc/sysctl.conf || echo fs.inotify.max_user_watches=524288 | tee -a /etc/sysctl.conf || echo 'cant set max_user_watches' && sysctl -p
sudo systemctl daemon-reload && sudo systemctl restart docker
Эти команды являются лишь частью того, что необходимо выполнить при разворачивании проекта. В приведённом примере видно, что команды сами по себе длинные, содержат много флагов, а значит, их трудно не только запомнить, но и вводить вручную. Постоянно вести документацию становится сложнее с ростом проекта, она неизбежно устаревает, а порог входа для новичков становится выше, ведь уже никто не в состоянии вспомнить всех деталей проекта. Некоторые такие команды необходимо использовать каждый день, и даже не один раз в день.
Со временем становится понятно, что нужен инструмент, способный объединить в себе подобные команды, предоставить к ним удобные шорткаты (более короткие и простые команды) и обеспечить самодокументацию проекта. Именно таким инструментом стал Makefile и утилита make
. Этот гайд расскажет, как использование этих инструментов позволит свести процесс разворачивания проекта к нескольким коротким и понятным командам:
# Bash
make setup
make start
make test
make
и MakefileMakefile — это файл, который хранится вместе с кодом в репозитории. Его обычно помещают в корень проекта. Он выступает и как документация, и как исполняемый код. Мейкфайл скрывает за собой детали реализации и раскладывает “по полочкам” команды, а утилита make
запускает их из того мейкфайла, который находится в текущей директории.
Изначально make
предназначалась для автоматизации сборки исполняемых программ и библиотек из исходного кода. Она поставлялась по умолчанию в большинство *nix дистрибутивов, что и привело к её широкому распространению и повсеместному использованию. Позже оказалось что данный инструмент удобно использовать и при разработке любых других проектов, потому что процесс в большинстве своём сводится к тем же задачам — автоматизация и сборка приложений.
Применение мейка в проектах стало стандартом для многих разработчиков, включая крупные проекты. Примеры мейкфайла можно найти у таких проектов, как Kubernetes, Babel, Ansible и, конечно же, повсеместно на Хекслете.
make
запускает цели из Makefile, которые состоят из команд:
# Makefile
цель1: # имя цели, поддерживается kebab-case и snake_case
команда1 # для отступа используется табуляция, это важная деталь
команда2 # команды будут выполняться последовательно и только в случае успеха предыдущей
Но недостаточно просто начать использовать мейкфайл в проекте. Чтобы получить эффект от его внедрения, понадобится поработать над разделением команд на цели, а целям дать семантически подходящие имена. Поначалу, перенос команд в Makefile может привести к свалке всех команд в одну цель с «размытым» названием:
# Makefile
up: # разворачивание и запуск
cp -n .env.example .env
touch database/database.sqlite
composer install
npm install
php artisan key:generate
php artisan migrate --seed
heroku local -f Procfile.dev # запуск проекта
Здесь происходит сразу несколько действий: создание файла с переменными окружения, подготовка базы данных, генерация ключей, установка зависимостей и запуск проекта. Это невозможно понять из комментариев и названия цели, поэтому будет правильно разделить эти независимые команды на разные цели:
# Makefile env-prepare: # создать .env-файл для секретов cp -n .env.example .env sqlite-prepare: # подготовить локальную БД touch database/database.sqlite install: # установить зависимости composer install npm install key: # сгенерировать ключи php artisan key:generate db-prepare: # загрузить данные в БД php artisan migrate --seed start: # запустить приложение heroku local -f Procfile.dev
Теперь, когда команды разбиты на цели, можно отдельно установить зависимости командой make install
или запустить приложение через make start
. Но остальные цели нужны только при первом разворачивании проекта и выполнять их нужно в определённой последовательности. Говоря языком мейкфайла, цель имеет пререквизиты:
# Makefile
цель1: цель2 # такой синтаксис указывает на зависимость задач — цель1 зависит от цель2
команда2 # команда2 выполнится только в случае успеха команды из цель2
цель2:
команда1
Задачи будут выполняться только в указанной последовательности и только в случае успеха предыдущей задачи. Значит, можно добавить цель setup
, чтобы объединить в себе все необходимые действия:
# Makefile
setup: env-prepare sqlite-prepare install key db-prepare # можно ссылаться на цели, описанные ниже
env-prepare:
cp -n .env.example .env
sqlite-prepare:
touch database/database.sqlite
install:
composer install
npm install
key:
php artisan key:generate
db-prepare:
php artisan migrate --seed
start:
heroku local -f Procfile.dev
Теперь развернуть и запустить проект достаточно двумя командами:
# Bash
make setup # выполнит последовательно: env-prepare sqlite-prepare install key db-prepare
make start
Благодаря проделанной работе Makefile, команды проекта вместе с флагами сведены в Makefile. Он обеспечивает правильный порядок выполнения и не важно, какие при этом задействованы языки и технологии.
Использование make
в проекте однажды может привести к появлению ошибки make: <имя-цели> is up to date.
, хотя всё написано правильно. Зачастую, её появление связано с наличием каталога или файла, совпадающего с именем цели. Например:
# Makefile
test: # цель в мейкфайле
php artisan test
# Bash
$ ls
Makefile
test # в файловой системе находится каталог с именем, как у цели в мейкфайле
$ make test # попытка запустить тесты
make: `test` is up to date.
Как уже говорилось ранее, изначально make
предназначалась для сборок из исходного кода. Поэтому она ищет каталог или файл с указанным именем, и пытается собрать из него проект. Чтобы изменить это поведение, необходимо в конце мейкфайла добавить .PHONY
указатель на цель:
# Makefile
test:
php artisan test
.PHONY: test
# Bash
$ make test
✓ All tests passed!
Запуск команд можно производить по одной: make setup
, make start
, make test
или указывать цепочкой через пробел: make setup start test
. Последний способ работает как зависимость между задачами, но без описания её в мейкфайле. Сложности могут возникнуть, если одна из команд возвращает ошибку, которую нужно игнорировать. В примерах ранее такой командой было создание .env-файла при разворачивании проекта:
# Makefile
env-prepare:
cp -n .env.example .env # если файл уже создан, то повторный запуск этой команды вернёт ошибку
Самый простой (но не единственный) способ «заглушить» ошибку — это сделать логическое ИЛИ прямо в мейкфайле:
# Makefile
env-prepare:
cp -n .env.example .env || true # теперь любой исход выполнения команды будет считаться успешным
Добавлять такие хаки стоит с осторожностью, чтобы не «выстрелить себе в ногу» в более сложных случаях.
Зачастую в команды подставляют параметры для конфигурации, указания путей, переменные окружения и make
тоже позволяет этим управлять. Переменные можно прописать прямо в команде внутри мейкфайла и передавать их при вызове:
# Makefile
say:
echo "Hello, $(HELLO)!"
# Bash
$ make say HELLO=World
echo "Hello, World!"
Hello, World!
$ make say HELLO=Kitty
echo "Hello, Kitty!"
Hello, Kitty!
Переменные могут быть необязательными и содержать значение по умолчанию. Обычно их объявляют в начале мейкфайла.
# Makefile
HELLO?=World # знак вопроса указывает, что переменная опциональна. Значение после присвоения можно не указывать.
say:
echo "Hello, $(HELLO)!"
# Bash
$ make say
echo "Hello, World!"
Hello, World!
$ make say HELLO=Kitty
echo "Hello, Kitty!"
Hello, Kitty!
Некоторые переменные в Makefile имеют названия отличные от системных. Например, $PWD
называется $CURDIR
в мейкфайле:
# Makefile
project-env-generate:
docker run --rm -e RUNNER_PLAYBOOK=ansible/development.yml \
-v $(CURDIR)/ansible/development:/runner/inventory \ # $(CURDIR) - то же самое, что $PWD в терминале
-v $(CURDIR):/runner/project \
ansible/ansible-runner
В рамках данного гайда было рассказано об основных возможностях Makefile и утилиты make
. Более плотное знакомство с данным инструментом откроет множество других его полезных возможностей: условия, циклы, подключение файлов. В компаниях, где имеется множество проектов, написанных разными командами в разное время, мейкфайл станет отличным подспорьем в стандартизации типовых команд: setup start test deploy ...
.
Возможность описывать в мейкфале последовательно многострочные команды позволяет использовать его как «универсальный клей» между менеджерами языков и другими утилитами. Широкая распространённость этого инструмента и общая простота позволяют внедрить его в свой проект достаточно легко, без необходимости доработок. Но мейкфайл может быть по-настоящему большим и сложным, это можно увидеть на примере реальных проектов:
Мейкфайлы, использованные при составлении гайда:
Что такое компилятор? » Универсальный файл MakefileМгновенно делитесь кодом, заметками и фрагментами.
Универсальный Makefile для C / C ++
# — вкл / | |
# — *.h | |
# — src / | |
# — * .c | |
# — * .cpp | |
# — объект / | |
# — * .o | |
# — основной | |
TARGET: = main | |
ИСТОЧНИКИ: = $ (подстановочный знак src / *.c src / *. cpp) | |
ОБЪЕКТОВ: = $ (patsubst src%, obj%, $ (patsubst% .c,%. O, $ (patsubst% .cpp,%. O, $ (SOURCES)))) | |
ВКЛЮЧИТЬ: = -I. | |
LIBPATH: = | |
LIBS: = | |
ФЛАГИ: = -Стена | |
CCFLAGS: = $ (FLAGS) -std = c99 | |
CXXFLAGS: = $ (ФЛАГИ) | |
CC: = gcc | |
Cxx: = g ++ | |
все: $ (ОБЪЕКТЫ) | |
$ (CC) $ (CCFLAGS) $ (INCLUDE) $ (OBJECTS) -o $ (TARGET) $ (LIBPATH) $ (LIBS) | |
%.o: ../src/%.c | |
$ (CC) $ (CCFLAGS) $ (ВКЛЮЧИТЬ) -c $ <-o $ @ | |
% .o: ../src/%.cpp | |
$ (CXX) $ (CXXFLAGS) $ (ВКЛЮЧИТЬ) -c $ <-o $ @ | |
.PHONY: чистая помощь | |
чистых: | |
rm -rf obj / * | |
п.м. -ф $ (ЦЕЛЬ) | |
справка: | |
@grep -E ‘^ [a-zA-Z _-] + :.*? ##. * $$ ‘$ (MAKEFILE_LIST) | сортировать | awk ‘BEGIN {FS = «:. *? ##»}; {printf «\ 033 [36m% -30s \ 033 [0m% s \ n», $$ 1, $$ 2} ‘ |
Мгновенно делитесь кодом, заметками и фрагментами.
Минимальный и универсальный make-файл для языка C
CC = gcc | |
CFLAGS = -Wall -Wextra -Wpedantic | |
LDFLAGS = | |
ИСТОЧНИКИ = $ (подстановочный знак *.в) | |
ОБЪЕКТОВ = $ (ИСТОЧНИКИ: .c = .o) | |
ИСПОЛНИТЕЛЬНЫЙ = exec | |
все: $ (ВЫПОЛНИТЕЛЬНО) | |
./$(EXECUTABLE) | |
$ (ИСПОЛНИТЕЛЬНЫЙ): $ (ОБЪЕКТЫ) | |
$ (CC) $ (CFLAGS) $ (ОБЪЕКТЫ) -o $ (ИСПОЛНИТЕЛЬНЫЙ) | |
$ (ОБЪЕКТЫ): $ (ИСТОЧНИКИ) | |
$ (CC) $ (CFLAGS) -c $ <-o $ @ | |
чистых: | |
п.м. $ (ИСПОЛНИТЕЛЬНЫЙ) $ (ОБЪЕКТЫ) |
Я часто использовал Make для небольших проектов, но для более крупных это было слишком утомительно. До недавнего времени я хотел, чтобы моя система сборки выполняла за меня четыре вещи, которые я не знал, как сделать в Make:
Вот простой Makefile, который будет делать все это и работать с C, C ++ и сборкой:
TARGET_EXEC? = А.вне
BUILD_DIR? = ./Build
SRC_DIRS? = ./Src
SRCS: = $ (shell find $ (SRC_DIRS) -name * .cpp -or -name * .c -or -name * .s)
OBJS: = $ (SRCS:% = $ (BUILD_DIR) /%. O)
DEPS: = $ (OBJS: .o = .d)
INC_DIRS: = $ (поиск оболочки $ (SRC_DIRS) -тип d)
INC_FLAGS: = $ (addprefix -I, $ (INC_DIRS))
CPPFLAGS? = $ (INC_FLAGS) -MMD -MP
$ (BUILD_DIR) / $ (TARGET_EXEC): $ (OBJS)
$ (CC) $ (OBJS) -o $ @ $ (LDFLAGS)
# сборка
$ (BUILD_DIR) /%. S.o:% .s
$ (MKDIR_P) $ (dir $ @)
$ (AS) $ (ASFLAGS) -c $ <-o $ @
# c исходный код
$ (BUILD_DIR) /%.c.o:% .c
$ (MKDIR_P) $ (dir $ @)
$ (CC) $ (CPPFLAGS) $ (CFLAGS) -c $ <-o $ @
# c ++ исходный код
$ (BUILD_DIR) /%. Cpp.o:% .cpp
$ (MKDIR_P) $ (dir $ @)
$ (CXX) $ (CPPFLAGS) $ (CXXFLAGS) -c $ <-o $ @
.PHONY: чистый
чистый:
$ (RM) -r $ (BUILD_DIR)
-включить $ (DEPS)
MKDIR_P? = Mkdir -p
Не так уж и плохо!
Кроме того, если вас не интересуют сборки вне исходного кода, вы можете использовать еще более простой Makefile, который использует преимущества встроенных неявных правил:
ЦЕЛЬ? = А.вне
SRC_DIRS? = ./Src
SRCS: = $ (shell find $ (SRC_DIRS) -name * .cpp -or -name * .c -or -name * .s)
OBJS: = $ (добавляет суффикс .o, $ (базовое имя $ (SRCS)))
DEPS: = $ (OBJS: .o = .d)
INC_DIRS: = $ (поиск оболочки $ (SRC_DIRS) -тип d)
INC_FLAGS: = $ (addprefix -I, $ (INC_DIRS))
CPPFLAGS? = $ (INC_FLAGS) -MMD -MP
$ (ЦЕЛЬ): $ (OBJS)
$ (CC) $ (LDFLAGS) $ (OBJS) -o $ @ $ (LOADLIBES) $ (LDLIBS)
.PHONY: чистый
чистый:
$ (RM) $ (ЦЕЛЬ) $ (OBJS) $ (DEPS)
-включить $ (DEPS)
Чтобы использовать один из них, поместите код Make в файл с вызовом Makefile
(убедитесь, что символы TAB копируются! Make очень придирчивы к ним) и весь исходный код и заголовки в каталоге или подкаталоге ./ src
(вы можете изменить этот каталог, изменив SRC_DIRS). Затем убедитесь, что CC и CFLAGS установлены на то, что вам нужно для вашего проекта, или просто используйте настройки по умолчанию.
Затем введите и сделайте
.
Если у вас возникнут проблемы, может оказаться полезным выполнение команды make -d
.
Вот обзор того, как это работает:
Я хочу, чтобы все артефакты из сборки попали в какой-то каталог (я обычно называю его «./build»), отдельный от источника.Это позволяет легко выполнить чистку (всего rm -rf ./build
), даже если там останутся другие артефакты, кроме тех, которые сгенерированы с помощью Make. Это также делает многое другое, например, поиск источника с помощью grep'а, намного приятнее.
Для того, чтобы сделать это в Make, вам в основном нужно просто добавить выходной каталог в начало правил шаблона. Например, вместо шаблона типа: % .o:% .c
, который будет отображать ваши файлы .c для файлов .o в том же каталоге, вы можете использовать $ (BUILD_DIR)%.о:% .c
.
Обработка зависимостей заголовков - , пожалуй, самая утомительная вещь в использовании классической техники Make. Тем более, что, если вы его испортите, вы не получите явных ошибок - вещи просто не будут повторно компилироваться, когда они должны быть. Это может привести к тому, что файлы .o имеют разные представления о том, как выглядят типы или прототипы.
Здесь есть документация по этому поводу. Однако документы, похоже, предполагают, что файлы зависимостей генерируются на отдельном этапе от этапа компиляции, что усложняет ситуацию.
Если вы генерируете файлы зависимостей как часть этапа компиляции, все становится намного проще. Чтобы сгенерировал файлов зависимостей, все, что вам нужно сделать, это добавить несколько флагов в команду компиляции (поддерживается как Clang, так и GCC):
-MMD -MP
DEPS: = $ (OBJS: .o = .d)
-включить $ (DEPS)
Сначала найдите все исходные файлы в указанных исходных каталогах.Самый простой и быстрый способ, который я нашел, - это просто раскошелиться и использовать find
.
Я использовал похожую технику для генерации флагов включаемого каталога. Найдите все каталоги в указанных исходных каталогах:
INC_DIRS: = $ (shell find $ (SRC_DIRS) -type d)
-I
: INC_FLAGS: = $ (addprefix -I, $ (INC_DIRS))
Надеюсь, эти методы будут вам полезны.
Как и любой разработчик, мне нравится использовать правильный инструмент для работы - когда дело доходит до кодирования проектов, выбор языка может значительно повлиять на производительность и рабочий процесс проекта. будущее. Для быстрых CLI и веб-проектов мне нравится использовать Python; для коротких одноразовых и специфичных для предметной области скриптов подойдет оболочка; для собственных примитивов параллелизма и простого языка я использую Golang.Многие языки, которые захватывают мир штормом, такие как Golang, Rust, Kotlin, Crystal и Nim, имеют встроенные или другие общепринятые системы сборки, которые относительно легко использовать для создания легко собираемых и устанавливаемых пакетов. Однако, будучи студентом-электротехником, который часто переходит на языки более низкого уровня, такие как C и C ++, системы сборки проектов представляют собой более серьезный барьер для входа. Чтобы решить эту проблему, у меня есть относительно простой «универсальный» Makefile для C и C ++ (и смешанный), который можно легко адаптировать для многих проектов.
Я также экспериментировал с CMake как с системой мета-сборки. CMake и подобные утилиты имеют свои преимущества - они упрощают кросс-компиляцию, их можно использовать с множеством различных систем сборки (даже одновременно), такими как XCode, Make, Ninja и т. Д. Однако я обнаружил, что CMake позволяет будет излишним для небольших проектов с небольшим количеством (0-5) исполняемых целей. Этот Makefile лучше работает с контролем версий (меньше вещей нужно вставлять в .gitignore) и требует меньшего когнитивного понимания - обзор неявных правил Make охватывает почти все.
1 |
|
Моя версия добавляет CXXFLAGS и CFLAGS, а также переключатель отладчика для компиляции GCC с отладочными символами.
ОбновлениеПри разработке проекта samurai-c ++ я обнаружил, что мне нужны две цели: одна утилита командной строки, которая в конечном итоге станет конечным продуктом, и один двоичный файл модульного теста для запуска во время разработки.Я пытался выполнить это разделение раньше, но столкнулся с проблемами, связанными с наличием нескольких списков объектов и зависимостей, которые мешали друг другу при вызове -include (DEPS). Я придумал следующее решение, которое поддерживает все объекты в общем списке объектов, все зависимости файлов, но держит два файла с функциями main () отдельно друг от друга, чтобы избежать ошибок компоновщика.
Я изменил объявления переменных на следующие:
1 | TARGET_ |
1 | .PHONY: все |
Я часто работаю на своем нетбуке, поэтому предпочитаю использовать Sublime Text с Makefiles вместо полнофункциональных IDE. Для автоматизации процесса сборки я построил (с помощью Василия Пикарда и примеров из Интернета) универсальный Makefile. Предполагается следующая структура файлов.
Все исходники помещаются в подкаталог src
. Промежуточные объектные файлы помещаются в подкаталог obj
, он должен быть создан перед компиляцией.Полученный двоичный файл помещается в подкаталог bin
. Если вы используете gengetopt в качестве парсера аргументов командной строки, назовите файл ggo как cmdline.ggo
и * .c
и * .h Файлы
будут обновлены автоматически при изменении ggo.
Следующий make-файл настроен на использование компиляторов mpi, включает библиотеки OpenGL, CUDA и GLUT, а также компилирует исходный код CUDA. Не стесняйтесь удалять ненужные фрагменты и изменять двоичное имя приложения (в первой строке).
ПРИЛОЖЕНИЕ: = bin / app
ИСТОЧНИКИ: = $ (подстановочный знак src / *. Cpp src / *. Cu src / *. C)
ОБЪЕКТЫ: = $ (patsubst src%, obj%, $ (patsubst% .cu,%. Device.o, $ (patsubst% .cpp,%. O, $ (patsubst% .c,%. O, $ (ИСТОЧНИКИ) )))))
ВКЛЮЧИТЬ: = -I / usr / local / cuda / include
LIBPATH: = -L / usr / локальный / cuda / lib64
LIBS: = -lcudart -lGL -lglut
ФЛАГИ: = -O3 -ffast-math -Wall -Werror -fopenmp
CCFLAGS: = $ (ФЛАГИ)
CXXFLAGS: = $ (ФЛАГИ) -std = c ++ 0x
GENCODE_FLAGS: = -gencode arch = compute_20, code = sm_20 -gencode arch = compute_30, code = sm_30 -gencode arch = compute_35, code = sm_35
NVCCFLAGS: = $ (GENCODE_FLAGS) --compiler-options -fno-strict-aliasing -lineinfo -use_fast_math -Xptxas -dlcm = cg
CC: = mpicc
CXX: = mpicxx
NVCC: = / usr / local / cuda / bin / nvcc
все: $ (ОБЪЕКТЫ)
$ (CXX) $ (CXXFLAGS) $ (ВКЛЮЧИТЬ) $ (ОБЪЕКТЫ) -o $ (ИМЯ ПРИЛОЖЕНИЯ) $ (LIBPATH) $ (LIBS)
obj / cmdline.о: src / cmdline.c
$ (CC) -Wno-unused-but-set-variable -c $ <-o $ @
src / cmdline.c: src / cmdline.ggo
gengetopt --input = src / cmdline.ggo --output-dir = src --include-getopt
% .o: ../src/%.c
$ (CC) $ (CCFLAGS) $ (ВКЛЮЧИТЬ) -c $ <-o $ @
% .o: ../src/%.cpp
$ (CXX) $ (CXXFLAGS) $ (ВКЛЮЧИТЬ) -c $ <-o $ @
% .device.o: ../src/%.cu
$ (NVCC) $ (NVCCFLAGS) -c $ <-o $ @
чистый:
rm -rf obj / *
rm -f $ (ИМЯ ПРИЛОЖЕНИЯ)
ПроектMakefiles Project - это набор универсальных make-файлов для сборки любого проекта. с инструментами Gnu (gcc, Gnu make и т. д.). Идея в том, что вы пишете тривиальный Makefile, который просто включает эти универсальные make-файлы, а все остальное делает для ты. Это позволяет очень легко создавать новые проекты и обеспечивать согласованность. сборок в мультибиблиотечном проекте.
Эти правила выполняют следующие задачи:
Примечание: Эти файлы предназначены *** ТОЛЬКО для Gnu make ***.
Make-файл содержит набор правил. Объем написания правил ограничен синтаксис make-файла. Поэтому было необходимо ограничить гибкость универсального make-файла для возможности записи это вообще.
Файл gcc.mak должен быть включен в ваш Makefile, чтобы установить значение по умолчанию. сделать правила для gcc.
включить ../makefiles/gcc.mak
Или любой другой путь к файлу gcc.mak.Относительный путь, а не рекомендуется абсолютный путь.
Вам необходимо определить переменные в вашем Makefile до того, как будет включать контролировать, что будет построено:
Это указывает, что вы создаете программу (исполняемый образ), и путь дает как каталог, так и имя изображения.
например ИЗОБРАЖЕНИЕ: = демо
Это означает, что вы создаете общую библиотеку и имя это необработанное имя библиотеки i.е. без префикса lib или суффикса .so.
например ПОДЕЛИТЬСЯ: = демо
Будет создана разделяемая библиотека libdemo.so.
Без IMAGE или SHARED make-файл создает статическую библиотеку, содержащую все скомпилированные объектные файлы.
Разделенный пробелами список библиотечных каталогов для включения / связывания в сборку. Только библиотеки управляемая этой системой make, и набор правил должен быть в списке.См. Позже, как управлять сторонние библиотеки.
например БИБЛИОТЕКИ: = ../stlplus3/containers
Каждый путь должен указывать на исходный каталог проекта, которым также управляет система makefile.
Обратите внимание, что часть пути, используемая для создания имени проекта - т.е. последняя часть должна быть именем каталога и не должна быть "..". В в этом случае название проекта - «контейнеры».
например БИБЛИОТЕКИ: = ../stlplus3/source
В этом случае суффикс «/ source» игнорируется, а имя проекта - «stlplus3».Это имя проекта должно быть именем каталога и не должно быть "..".
В дополнение к этим ключевым переменным, которые управляют тем, что должно быть построено, есть другие переменные для управления детали сборки. Эти переменные-модификаторы следует добавить ПОСЛЕ включения файла gcc.mak. Большинство полезны те, которые позволяют включать другие библиотеки в сборку. которые не управляются этой системой make.
Изменяемые переменные:
Флаги препроцессора, общие для компиляций C и C ++.Большинство распространенными и полезными из них являются дополнительные пути включения для библиотек не управляется этой системой make и, следовательно, не находится в БИБЛИОТЕКАХ список.
Устанавливает дополнительные параметры для компилятора gcc при компиляции кода C только (файлы .c). Обычно это параметры, специфичные для языка C.
например CFLAGS + = -O3
Устанавливает дополнительные параметры для компилятора gcc при компиляции кода C ++. (.cpp файлы) только. Обычно это параметры, специфичные для языка C ++.
например CXXFLAGS + = -ftemplate-depth-50
Устанавливает дополнительные флаги для компоновщика. Они размещаются с до . объектные файлы в команде ссылки
например LDFLAGS + = -s
Дополнительные объектные файлы или библиотеки, которые должны быть включены в ссылку, которые не управляются этим сделать систему.Они помещаются после объектных файлов в команде связывания.
Переменная LDLIBS может содержать имена объектных файлов или архивных библиотек:
например LDLIBS + = -lxyz
Итак, в приведенном выше случае линкуется библиотека libxyz.a.
Этот параметр также используется для создания зависимости от разделяемых библиотек (.dll в Windows или .so в Unix):
например LDLIBS + = -lxyz
Таким образом, в приведенном выше случае библиотека, с которой выполняется компоновка, - это либо xyz.dll в Windows или libxyz.so в Unix.
Вам может потребоваться использовать верхний регистр -L, чтобы указать путь поиска для этих библиотек:
например LDLIBS + = -L ../ xyz -lxyz
Обратите внимание на использование '+ =' not ': ='. Вы добавляете дополнительные параметры к существующим параметры, созданные системой make.
Есть также некоторые переменные, которые можно использовать для включения или выключения. определенные варианты. Они принимают значения «включено» или «выключено»:
При включении создает версию выпуска заявление.У этого нет отладочной информации и компилятора включена оптимизация для создания небольшой быстрой программы. Когда выключен, это создает отладочную версию с полным отладчиком информация для использования с gdb и с оптимизацией компилятора отключен. Примечание: обычно это включается из командной строки, а не из Makefile: см. «Варианты сборки».
При включении строит профилирующую версию приложения. для использования с профилировщиком gprof.В выключенном состоянии это создает нормальная версия. Примечание: обычно это включается командой строку, а не из Makefile: см. Варианты строительства.
При включении включает поддержку символов Юникода. По факту, это просто включает директивы компилятора -DUNICODE и -D_UNICODE, поэтому программист должен убедиться, что они привязаны к Поддержка Unicode. Большинство библиотек следуют этому соглашению.
При включении заставляет компилятор связывать, где это возможно, со статическими библиотеками C и C ++ для минимизации зависимости от общих библиотеки.Это устраняет зависимость от общей библиотеки C ++ STL и может удалить и другие зависимости, в зависимости от заявление. Вам все равно нужно проверить оставшиеся неразрешимые зависимости разделяемых библиотек. Если выключено, build будет использовать общие библиотеки, где это возможно, чтобы минимизировать это размер приложения.
В выключенном состоянии дает краткую однострочную сводку по каждому build команду, если нет ошибок, в этом случае стандартная ошибка отчет дан.При включении команды сборки переключился в подробный режим, чтобы дать больше диагностики.
Есть несколько целей, которые можно использовать с make. Идея в том, что вы запускаете make из командной строки с такой целью:
$ make <цель>
Цель не является обязательной; если отсутствует, то цель по умолчанию - использовал.
Цели, которые в настоящее время поддерживаются проектом Makefiles:
Эквивалент цели 'build', но есть обстоятельства, когда вы можете изменить набор целей, отображаемых на «все» цели.
Скомпилируйте все исходные файлы и свяжите образ, если он есть (т.е. если установлена переменная IMAGE) или разделяемая библиотека, если есть равен единице (т.е. установлен SHARED).
Запустить программу, если она есть (т. Е. Если переменная IMAGE набор). Сначала будет запущена цель сборки.
Удалите промежуточные файлы, созданные во время компиляции.
Удалить все файлы, созданные во время компиляции, включая временные файлы, библиотеки и программа, если таковая имеется.
Это полезно, если вы внесли изменения в параметры компиляции и вам нужно начать с чистого листа.
Цели можно комбинировать в командной строке. Например, чтобы построить и запустить проект:
$ make build run
Или даже, чтобы удалить все сгенерированные файлы, выполните сборку из stratch и затем запустите:
$ сделать чистую сборку запустить
Имя проекта - это либо имя каталога, если каталог называется "источником", и в этом случае каталог выше что используется.Makefile использует имя проекта для создания имя библиотеки.
Например, вот структура каталогов проекта STLplus:
В приведенном выше примере для Makefile, выделенного жирным шрифтом, имя проекта - «stlplus». Это потому, что каталог, содержащий Makefile, называется "источником", поэтому каталог выше что используется.Этот каталог называется «stlplus».
Можно было бы использовать более простую структуру каталогов:
В этом случае имя проекта по-прежнему «stlplus». Это потому, что каталог, содержащий исходный код, называется "stlplus", поэтому он используется как название проекта.
Имена проектов должны быть уникальными в рамках разработки конкретного приложения.Например, вы можете работать над приложением, которое разделено на несколько проектов для кодирования. Каждый проект, составляющий у приложения должно быть другое название проекта.
В проекте весь исходный код, то есть все заголовки (.h или .hpp) и файлы реализации (.c или .cpp) - должны находиться в одном каталоге. Makefile должен находиться в этом же каталоге. Структура с несколькими каталогами должна быть построен как несколько проектов, по одному на каталог.
Универсальный make-файл использует расширения файлов для определения типа компиляция для использования:
Любой файл с этими расширениями в каталоге проекта будет скомпилирован с использованием компилятор, соответствующий его типу.
Итак, если вы используете расширения .c для файлов C ++, у вас будут проблемы. Полагаю это хорошая практика - четко указать, является ли файл C или C ++, поэтому это особенность, а не ошибка.
Еще рекомендую:
Когда вы компилируете файлы с помощью универсального make-файла, он сохраняет все скомпилированные объектный код в подкаталоге исходного каталога. Вы можете убрать просто удалив этот рабочий каталог.
Имя рабочего каталога является производным от операционной системы и процессора. тип компьютера, на котором вы работаете.Универсальный make-файл содержит набор правил выработки этого названия.
Причина этого в том, что некоторые люди работают над одним и тем же исходный код с разными компиляторами и, возможно, даже с дисками, которые доступны по сети с одного из множества различных компьютеры. Система makefile хранит компиляции для разных платформы раздельные. Это означает, что вы можете, например, скомпилировать свой код на одной платформе, а затем снова скомпилировать для другой платформы. В Система makefile хранит рабочие каталоги отдельно.
Имя каталога состоит из трех частей. Например:
GNULINUX-альфа-отладка
Первая часть имени - это общее имя операционной системы, в данном случае Gnu / Linux. В Операционная система написана в верхнем регистре, чтобы подчеркнуть, что макрос компилятора GNULINUX будет определен как директива компилятора (в данном случае -DGNULINUX) и может использоваться в исходном коде в "#ifdef GNULINUX" директивы препроцессора.
Вторая часть имени - это тип ЦП - в данном случае «альфа», то есть 64-битный DEC Alpha. ПРОЦЕССОР.
Третья часть имени - вариант сборки - в данном случае «отладка». Этот означает, что это отладочная сборка программного обеспечения - см. следующий раздел для подробнее о вариантах сборки и способах их создания.
Система make может строить различные варианты проекта в зависимости от аргумент после make.
Обратите внимание, что эти варианты создаются путем указания значений используемых переменных. для управления типом сборки.См. Определения переменных RELEASE выше, GPROF, UNICODE, STATIC и VERBOSE. Фактически любая переменная, управляющая сборкой, может быть установленным либо в Makefile, то есть всегда использовать одно и то же значение, либо из командная строка, и в этом случае это разовая сборка с этой опцией.
Идея в том, что вы разрабатываете с использованием отладочной версии. Это все символическое информация, необходимая для запуска отладчика, такого как gdb от Gnu, а также всех макросы, управляемые директивой препроцессора NDEBUG. Директива NDEBUG это стандартный метод ANSI C для включения / исключения кода отладки в вашем источник - используется макросом C assert (expr), а также расширенным макросы отладки, предоставляемые отладкой заголовка библиотеки STLplus.hpp.
Вы можете в любой момент создать вариант профилирования для использования с gprof Gnu. Этот позволяет выявлять любые проблемы с производительностью и выборочно оптимизировать код на основе профилей производительности. Обычно 95% или более программы НЕ производительность критична, поэтому оптимизация всего - огромная трата усилий. Профилирование позволяет сосредоточить внимание на тех 5% программы, которые действительно могут выгода от оптимизации.
Обратите внимание, что версия профилирования построена с тем же уровнем оптимизации, что и версия выпуска, чтобы дать точное представление о том, как версия выпуска будет выполнять.
Как только вы убедитесь, что ваша программа полностью свободна от ошибок (хорошо, только шутя) и ослепительно быстро (да, хорошо, еще раз пошутил), вы можете построить вариант выпуска для отгрузки заказчику. Это будет не только около четырех раз быстрее, чем вариант отладки, но также будет намного меньше. Это также больше трудно реконструировать, потому что он не содержит отладки Информация.
Существует отдельный набор правил make для обработки структур подкаталогов.Например, чтобы создать проект с двумя подпроектами, у вас может быть следующая структура:
Итак, я хочу написать Makefile (выделенный жирным шрифтом выше) для «проекта» верхнего уровня. каталог, в котором создается основной проект путем создания двух подпроектов.
Создайте проект / Makefile, содержащий одну строку:
включить ../makefiles/subdirectories.mak
Это правило ищет набор подкаталогов, которые сами содержат Makefile и делает их.
Существует дополнительный универсальный make-файл для использования при сборке программы wxWidgets.Этот make-файл должен быть включен после gcc.mak файл.
Например:
ИЗОБРАЖЕНИЕ: = демонстрация БИБЛИОТЕКИ: = ../stlplus3 включить ../makefiles/gcc.mak включить ../makefiles/wx.mak
Файл wx.mak добавляет дополнительные параметры компилятора и компоновщика для wxWidgets. Оно использует сценарий wx-config, поставляемый с wxWidgets, для адаптации к вашей установке - другими словами, вам нужно запустить "configure", "make" и "make install" при сборке wxWidgets. так что программа wx-config находится на пути.
По умолчанию приложение wxWidgets создается с использованием общего доступа. библиотеки для библиотек wxWidgets. Это соответствует конфигурация wxWidgets по умолчанию. Однако вы можете построить приложение без каких-либо зависимостей разделяемой библиотеки wxWidgets - как статическая сборка - указав параметр WXSTATIC в Makefile:
ИЗОБРАЖЕНИЕ: = демонстрация БИБЛИОТЕКИ: = ../stlplus3 WXSTATIC: = вкл. включить ../makefiles/gcc.mak включить ../makefiles/wx.мак
Для правильной сборки у вас должна быть не-общая версия wxWidgets установлен, что достигается путем сборки wxWidgets с Параметр "--disable-shared" для сценария настройки.
Примечание: это отличается от параметра СТАТИЧЕСКИЙ, который управляет зависит ли приложение от разделяемых библиотек C ++. В Параметр WXSTATIC определяет, зависит ли приложение от Общие библиотеки wxWidgets.
Возможно установить несколько разных версий wxWidgets на в то же время и выбрать, какой из них использовать во время сборки.Этот выбор поддерживается с помощью параметра WXVERSION в Makefile:
ИЗОБРАЖЕНИЕ: = демонстрация БИБЛИОТЕКИ: = ../stlplus3 WXSTATIC: = вкл. WXVERSION: = 3.0 включить ../makefiles/gcc.mak включить ../makefiles/wx.mak
Будет выбрана версия 3.0 wxWidgets и построено приложение с ее помощью.
Вот типичный Makefile для создания библиотеки статических объектов:
БИБЛИОТЕКИ: = ../stlplus3/portability включить ../makefiles/gcc.mak
Вот типичный Makefile для создания исполняемого образа:
ИЗОБРАЖЕНИЕ: =../bin/ccolour БИБЛИОТЕКИ: = ../stlplus3/portability включить ../makefiles/gcc.mak
Чтобы показать всю картинку, вот мультибиблиотечный проект для "ccolour" программа со структурой каталогов и make-файлами, использованными для ее создания. В Проект ccolour использует проект stlplus3. Чтобы построить весь проект, вы необходимо зайти в исходный каталог каталога ccolour и запустить сделать:
Мы разрабатываем программы в среде Linux, Незаменим для написания собственного Makefile
, One Немного более крупные проекты будут содержать много файлов.c / .cpp исходные файлы. Если мы будем использовать gcc / g ++ для компиляции каждого исходного файла один за другим, эффективность будет намного ниже, но если мы сможем написать Makefile, тогда нужно будет только выполнить make, что значительно повысит эффективность разработки.
, но Для Makefile
существует множество грамматических правил, и из-за отсутствия справочных материалов новичкам все еще трудно писать, что часто пугает многих. Ниже мы представляем несколько более общих и кратких Makefile, если вы Слегка модифицировали
Его можно использовать в ваших собственных проектах.
Как я только что сказал, в Makefile есть много правил, может показаться, что вы находитесь в процессе копирования, потому что Различные системы будут вызывать ненужные ошибки во время процесса копирования
, Makefile непригоден для использования, рекомендуется перейти на github, чтобы клон
адрес github
Я загрузил в общей сложности 4 общих make-файла, я использую MyMakefile, у каждого есть свои преимущества и недостатки, пожалуйста, не стесняйтесь !!!
Разместите MyMakefile здесь:
########################################################################### ################
################## Поддержка гибридной компиляции C / C ++ ###################### #####
########################################################################## ##############
PRJ_ROOT = # Изменять не нужно, здесь вы можете добавить путь к заголовочному файлу и т. Д., за которым следует LDFLAGS для удобства использования
CC = g ++ # Компилятор, скомпилировать файл C, выбрать gcc, скомпилировать файл C ++, выбрать g ++ (лучше всего выбрать g ++, потому что он совместим с C)
CFLAGS = # Если вам нужно отлаживать, добавьте сюда опцию -g, вы также можете добавить команды опций ответа в соответствии с вашими потребностями
CPPFLAGS = # То же, что и выше
LDFLAGS = -std = c ++ 11 -lpthread ########################################################################## ##############
########### Исходный файл, для каждой дополнительной цели добавьте следующий абзац #############
########################################################################## ############## # Исходный файл list1
я: = 1
SOURCES_CPP _ $ (i): = test.cpp # Добавьте и измените исходный код CPP, необходимый для текущей цели, здесь
SOURCES_C _ $ (i): = # Добавить и изменить здесь исходный код C, необходимый для текущей цели
TARGET _ $ (i): = testcpp # имя цели
OBJS_CPP _ $ (i): = $ (patsubst% .cpp,%. O, $ (SOURCES_CPP _ $ (i)))
OBJS_C _ $ (i): = $ (patsubst% .c,%. O, $ (SOURCES_C _ $ (i)))
OBJS _ $ (i): = $ (OBJS_CPP _ $ (i)) $ (OBJS_C _ $ (i)) # Исходный файл list2
я: = 2
ИСТОЧНИК_CPP _ $ (i): =
ИСТОЧНИК_C _ $ (i): = main.c
ЦЕЛЬ _ $ (i): = mainc
OBJS_CPP _ $ (i): = $ (patsubst% .cpp,%. O, $ (SOURCES_CPP _ $ (i)))
OBJS_C _ $ (i): = $ (patsubst%.c,%. o, $ (ИСТОЧНИКИ_C _ $ (i)))
OBJS _ $ (i): = $ (OBJS_CPP _ $ (i)) $ (OBJS_C _ $ (i)) ########################################################################## ##############
####### Цели и зазоры Для каждой дополнительной цели соответственно добавляется цель ############
########################################################################## ############## все: $ (TARGET_1) $ (TARGET_2)
@echo "выходной файл: $ (TARGET_1) $ (TARGET_2)"
чистый:
rm -f * .o * .d $ (ЦЕЛЬ_1) $ (ЦЕЛЬ_2) ########################################################################## ##############
########## Цели, каждый раз, когда вы добавляете цель, добавляйте следующий абзац ###############
########################################################################## ############## # цели1
$ (TARGET_1): $ (OBJS_1)
$ (CC) $ (OBJS_1) $ (LDFLAGS) -o $ (TARGET_1) # цели2
$ (TARGET_2): $ (OBJS_2)
$ (CC) $ (OBJS_2) $ (LDFLAGS) -o $ (TARGET_2) ########################################################################## ##############
########### Включить для каждой дополнительной цели добавьте следующую строку ################
########################################################################## ############## sinclude $ (OBJS_1 :.