G как компилировать несколько файлов

Обновлено: 07.07.2024

В статье вы научитесь создавать программу из нескольких файлов

Содержание

Объявления и определения

Рассмотрим задачу: надо вывести числа от N до 1, при этом для нечётных чисел надо писать odd $ , а для чётных even $ . Вывод должен выглядеть так:

Ради интереса решим задачу с помощью рекурсии:

Увы программа не компилируется. В C++ каждая функция должна быть объявлена или определена до первого использования, но в нашем случае printEvenRecursive использует printOddRecursive, а printOddRecursive использует printEvenRecursive! Мы не можем поместить определение одной функции выше другой так, чтобы каждая функция была объявлена перед использованием.

Но кроме определений функций в C++ есть объявления функций

  • Объявление (declaration) - это конструкция, которая зарезервирует идентификатор и опишет для компилятора его тип, но не раскроет деталей работы объявленной сущности.
  • Определение (definition) - это конструкция, которая не только зарезервирует идентификатор, но и раскроет реализацию связанной с ним сущности

Объявление функции похоже на определение функции, только вместо тела стоит точка с запятой:

Теперь мы можем переписать рекурсивный пример, просто разместив определения обеих функций в начале файла.

Хорошим стилем считается заранее и в одном месте писать объявления всех функций, кроме main. Вы можете писать объявления в начале cpp-файла или в заголовке. О заголовках читайте ниже.

Пишем свой заголовок

  • Заголовок может иметь и другое расширение файла, но не стоит нарушать джентльменских соглашений: используйте h или hpp
  • В заголовке пишут только объявления функций, а все определения можно и нужно помещать в cpp-файл

Создайте каталог, и разместите в нём файл print.h , в котором будут объявления функций. Скопируйте туда код, приведённый ниже.

Мы могли бы убрать из заголовка printEvenRecursive и printOddRecursive, сделав его чище, но сейчас для примера оставим.

Запомните правила хорошего тона:

Теперь создайте файл print.cpp , в котором будут реализованы функции из заголовка print.h . Скопируйте туда код, расположенный ниже.

В конце создайте файл main.cpp и скопируйте в него код:

Компоновка программы из нескольких файлов

Собирая программу из одного файла с помощью g++, вы на деле выполняли одним махом два действия:

  • компиляцию, в ходе которой исходный текст файла превращается в логическую модель (AST) и затем превращается в объектный код, в котором машинные коды смешаны со ссылками на внешние функции
  • компоновку, в ходе все внешние ссылки на функции заменяются на машинный код либо превращаются в ссылки на динамические библиотеки (dll/so, также известны как shared libraries)

Сейчас эти же действия мы выполним раздельно. Отройте терминал и введите последовательно две команды:

Если код в обоих cpp-файлах синтаксически правилен, то компилятор создаст два файла: main.o и print.o . Эти файлы называют объектными файлами (object files). Именно они содержат машинный код, смешанный со ссылками на внешние функции.

Вы можете дизассемблировать эти файлы, чтобы посмотреть, во что компилятор превратил ваш код. Для этого выполните команду objdump -d main.o .

Теперь мы вызовем g++ для компоновки объектных файлов. На выходе мы получим исполняемый файл print_executable.exe

На деле компилятор не будет компоновать: он передаст эту задачу утилите ld. Вызывать утилиту ld вручную мы не станем, потому что потребуются дополнительные флаги, которые включают компоновку со стандартной библиотекой C++.

Компоновка программы в CMake

CMake прячет факт раздельной компиляции файлов. Чтобы в CMake скомпоновать программу, состоящую из нескольких частей, просто перечислите эти файлы в add_executable.

Удалите файл print_recursive.exe :

Создайте файл CMakeFiles.txt с одной строкой:

Теперь выполните конфигурирование и сборку программы:

Мы почти закончили! Остался только один вопрос: почему в add_executable мы указали заголовок print.h , если он всё равно не компилируется сам по себе? Дело в том, что при любых изменениях в коде заголовка print.h вся программа должна быть пересобрана, но файл print.h сам по себе не компилируется. Добавление print.h в список исходников в CMake позволяет CMake следить за датой и временем модификации заголовка, чтобы решить, надо ли повторно собирать проект из-за изменений в заголовках.

Как только программы становятся больше, их следует разбивать на несколько файлов (в целях удобства и улучшения функциональности). Одним из преимуществ использования IDE является легкость в работе с n-ным количеством файлов. Мы уже знаем, как создавать и компилировать однофайловые проекты, добавление новых файлов не составит труда.

Многофайловые проекты в Visual Studio

В Visual Studio щелкните правой кнопкой мыши по имени вашего проекта в "Обозревателе решений" , затем "Добавить" > "Создать элемент. " :


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


Также вы можете добавлять файлы к вашему проекту через "Проект" > "Добавить новый элемент. " :



Многофайловые проекты в Code::Blocks

В Code::Blocks перейдите в "File" > "New" > "File. " :


Затем выберите "C/C++ source" и нажмите "Go" :


Затем "Next" (этого окна может и не быть):


Затем "C++" и опять "Next" :


Затем укажите имя нового файла (не забудьте расширение .cpp) и его расположение (нажмите на троеточие и выберите путь). Убедитесь, что поставлены все три галочки (они отвечают за конфигурации сборки). Затем нажмите "Finish" :


Готово! Файл добавлен.

Многофайловые проекты в GCC/G++

В командной строке вам нужно будет создать файл, указать его имя и подключить к компиляции, например:

g++ main.cpp add.cpp -o main

Пример многофайловой программы

Рассмотрим следующую программу, которая состоит из двух файлов.

std :: cout << "The sum of 3 and 4 is: " << add ( 3 , 4 ) << std :: endl ;

Попробуйте запустить эту программу. Она не скомпилируется, вы получите следующую ошибку:

add: идентификатор не найден

При компиляции кода, компилятор не знает о существовании функций, которые находятся в других файлах. Это сделано специально, чтобы функции и переменные с одинаковыми именами, но в разных файлах, не вызывали конфликт имен.

Тем не менее, в данном случае, мы хотим, чтобы main.cpp знал (и использовал) функцию аdd(), которая находится в add.cpp. Для предоставления доступа main.cpp к функциям add.cpp, нам нужно использовать предварительное объявление:

int add ( int x , int y ) ; // это нужно для того, чтобы main.cpp знал, что функция add() определена в другом месте std :: cout << "The sum of 3 and 4 is: " << add ( 3 , 4 ) << std :: endl ;

Теперь, когда компилятор будет компилировать main.cpp, он будет знать, что такое add(). Попробуйте запустить эту программу еще раз.

Что-то пошло не так!

Пункт №1: Если вы получили ошибку от компилятора, что функция add() не определена в main(), то, скорее всего, вы забыли записать предварительное объявление функции add() в main.cpp.

Пункт №2: Если вы получили следующую ошибку от линкера:

unresolved external symbol "int __cdecl add(int,int)" (?add@@YAHHH@Z) referenced in function _main

то возможных решений есть несколько:

a) Cкорее всего, add.cpp некорректно добавлен в ваш проект. Если вы используете Visual Studio или Code::Blocks, то вы должны увидеть add.cpp в "Обозревателе решений" в списке файлов вашего проекта или в панели проекта IDE. Если добавленного файла нет, то щелкните правой кнопкой мыши по вашему проекту и добавьте файл, как это показано выше, а затем повторите попытку компиляции вашего проекта.

б) Вполне возможно, что вы добавили add.cpp к другому проекту.

в) Вполне возможно, что добавленный файл не подключен к компиляции/линкингу. Щелкните правой кнопкой мыши по имени вашего добавленного файла и выберите "Свойства" :


Убедитесь, что пункт "Исключен из сборки" оставлен пустым или выбрано значение "Нет" :


Пункт №3: Не следует писать следующую строку в main.cpp:

Наличие этой строки приведет к тому, что компилятор вставит всё содержимое add.cpp непосредственно в main.cpp вместо того, чтобы рассматривать эти файлы как отдельные.

Разделите следующую программу на два файла (main.cpp и input.cpp): main.cpp должен содержать функцию main(), а input.cpp — функцию getInteger().

Помните, что для функции getInteger() вам понадобится предварительное объявление в main.cpp.

Ответ

int getInteger ( ) ; // предварительное объявление функции getInteger() (906 оценок, среднее: 4,87 из 5)

Урок №19. Прототип функции и Предварительное объявление

Комментариев: 50

Я так понимаю, что при включении в главный файл заголовочный файл библиотеки, которые были в заголовочном файле копируются, что только прибавляет веса главному файлу или все же копирует лишь функции?

Здравствуйте. А если у меня функция getInteger() будет определена в 2 и более файлах, то как файл с функцией main() поймет какой именно getInteger() мне требуется?

Я методом тыка уже определил что будет ошибка )

Юрий :

Если вы подключите больше одного файла с определением одной и той же функции в проект, то получите ошибку компиляции. Функция определяется 1 раз в 1 файле.

Юрий :

Смотрите решение в уроке №7.

Спасибо, Юрий! Замечательные уроки! Получаю удовольствие.. Возникают вопросы.. ищу на сайтах.. нахожу.. Будут посерьёзнее, намерен обращаться, если позволите!

Юрий :

Начал изучать С++ для создания игр на Unreal, но там все как то сложно.
Случайно наткнулся на ваши уроки, это же просто чудо какое то)
Спасибо за ваш труд.
Пожалуй накидаю плюсиков в карму автору)

Мне кажется стоило также указать что хорошим тоном является написать функцию в <name>.cpp, сделать её объявление в <name>.h, после чего подключить <name.h> в основном файле.

Вместо того чтобы писать объявления функций напрямую.

Первый файл с функцией int getInteger():

Может кто-нибудь знает как это все осуществить при помощи Xcode, или статью какую-нибудь по обучению использования этой среды.

А что сложного в Xcode? Всё по аналогии с VS, но со своими особенностями (если уж на то пошло). Можно нагуглить на крайний случай.

Юрий :

Здравствуйте я пишу в андроид с помощью Dcoder и хотел пройти тест в конце этого урока но у меня выдаёт ошибку.

Спасибо за уроки, хороший язык оказывается.

Срочно нужна помощь.
Начал программировать на андроид с приложения Dcoder(c++: GCC compiler 6.3 (знаю, что это неудобно и т. д., но лучше так, чем никак).
С этим уроком получилась зиминка из-за моего не состояния найти способ, как связать несколько файлов именно в этом приложении. Если кто-то что с этим делать, тогда пишите (буду очень благодарен). Автору спасибо за уроки. Всё очень доходчиво написано.

Это символ переноса строки, такая управляющая последовательность(и гуглите 🙂 )

Какая же чудесная находка для меня эти уроки) Автору огромное спасибо за проделанную работу за перевод и адаптацию

Юрий : Юрий :

Здравствуйте. Как добавлять файлы в Visual Studio 2017 если он на русском. Просто не очень понятно, переводчик не помогает.

Юрий :

Тогда я ошибся, и это чудесно =) Прошу прощения. Я не заметил ссылки, привык их искать где-то в аннотации.

Юрий :

Ничего, без проблем 🙂

Добрый день! При попытке добавить в функцию, которая находится в отдельном файле, "stdafx.h" компилятор выдаёт ошибку: не удаётся открыть файл включения stdafx.h: No such file or directory. Без stdafx.h всё нормально работает. Visual Studio 2015.

Юрий :

Сегодня читала статью с телефона. Очень удобный сайт)

Юрий :

Когда пишу файл add.cpp постоянно не идёт,это ж линкер мешает по моему. И что ему не так,когда твою программу скопировал,также всё:

Ошибка LNK2019 ссылка на неразрешенный внешний символ _main в функции "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) add.cpp 1

Юрий :

Вы сделали всё как в уроке? Правильно добавили файл? К тому проекту, что нужно?

Почему в VS нужно обязательно подключать библиотеку stdafx.h? Раньше, когда я учился по видеоурокам, я писал программы и без ее подключения. Но конечно есть одно но, я тогда немного изменил параметры создания проекта: поставил галочку на "Empty project" и удалил галочку на "Security Development Lifecycle (SDL) checks ". Может быть это как-то повлияло?

Юрий :

Зачем писать названия в VS (например Source Files) на английском, если в VS есть русский язык?

Начало работы с многофайловой компиляцией Linux и make-файлом

Каталог статей


В процессе программирования для нас невозможно поместить все в файл c, что значительно снизит нашу эффективность.Мы можем написать свои собственные файлы c в соответствии с различными функциями и, наконец, вызвать основную программу. Когда я впервые познакомился с vim, я знал только, что gcc можно использовать для компиляции и генерации исполняемых программ.Я всегда думал, что gcc является компилятором, но это не так.


GCC(Коллекция компиляторов GNU, Коллекция компиляторов GNU) - переводчик языков программирования, разработанный GNU. Набор компиляторов GNU включает в себя внешние интерфейсы языков C, C ++, Objective-C, Fortran, Java, Ada и Go, а также библиотеки для этих языков (например, libstdc ++, libgcj и т. Д.).
Хотя мы называем GCC компилятором языка C, процесс использования gcc для создания исполняемого файла из файла исходного кода языка C - это не просто процесс компиляции, а четыре взаимных Связанные шаги: предварительная обработка (также называемая предварительной обработкой, предварительной обработкой), компиляция, сборка и компоновка.

1. Предварительная обработка

2. Скомпилировать

Составление (составление) - это прохождение лексического и грамматического анализа. Убедившись, что все инструкции соответствуют грамматическим правилам, Переведите его в эквивалентное промежуточное представление кода или ассемблерный код. Оптимизационная обработка - относительно сложная технология в системе компиляции. Проблемы, связанные с этим, связаны не только с самой технологией компиляции, но также имеют большое отношение к аппаратной среде машины. Часть оптимизации - это оптимизация промежуточного кода, эта оптимизация не зависит от конкретного компьютера. Другая оптимизация в основном направлена ​​на генерацию целевого кода. Для первой оптимизации основная работа заключается в удалении общих выражений, оптимизации цикла (аутсорсинг кода, ослабление силы, изменение условий управления циклом, слияние известных величин и т. Д.), Распространение копий, удаление бесполезных назначений и т. Д. Последний тип оптимизации тесно связан со структурой аппаратного обеспечения машины.Самое важное соображение состоит в том, как в полной мере использовать значения переменных, хранящихся в аппаратных регистрах машины, для уменьшения количества обращений к памяти. Кроме того, как выполнять инструкции в соответствии с характеристиками аппаратного обеспечения машины (например, конвейер
line, RISC, CISC и т. д.), а также некоторые корректировки инструкций, чтобы сделать целевой код короче и повысить эффективность выполнения, что также является важной темой исследования.
Обычно используйте команду gcc -S hello.i для компиляции и создания файлов сборки, или вы можете выполнить компиляцию с помощью указанного компилятора. Когда вы используете компилятор ПК для компиляции, он создает файлы сборки x86. Компиляция компилятора будет генерировать файлы сборки ARM. Файлы сборки каждой архитектуры могут использоваться только в этой архитектуре. Мы можем выбирать разные компиляторы в соответствии с нашей архитектурой. Этопереносимость. Процесс использования кросс-компилятора ARM на ПК для создания исполняемых программ на платформе ARM называетсяКросс-компиляция。

3. Сборка

Процесс сборки (сборки) фактически относится к Процесс перевода кода на ассемблере в целевые машинные инструкции. Для каждой исходной программы на языке C, обработанной системой перевода, соответствующий целевой файл будет окончательно обработан посредством этого процесса. В целевом файле хранится машинный код целевой программы, эквивалентной исходной программе. Целевой файл состоит из сегментов. Обычно объектный файл состоит как минимум из двух разделов:
1. Сегмент кода (текстовый сегмент): этот сегмент содержит в основном инструкции программы. Этот раздел обычно доступен для чтения и выполнения, но не для записи;
2. Сегмент данных: в основном хранит различные константы, глобальные переменные и статические данные, используемые в программе. Сегменты общих данных доступны для чтения, записи и выполнения;
Мы можем создать файлы сборки с помощью команды gcc -c hello.s.

4. Ссылка

Объектный файл, созданный ассемблером, не может быть запущен сразу, и может быть много нерешенных проблем. Например, функция в исходном файле может ссылаться на символ, определенный в другом исходном файле (например, на переменную или вызов функции и т. Д.); Функция в файле библиотеки может быть вызвана в программе и так далее. Все эти проблемы могут быть решены только обработкой программы ссылки. Основная задача компоновщика - соединить связанные объектные файлы друг с другом, то есть соединить символы, на которые есть ссылки в одном файле, с определением символа в другом файле, чтобы все эти объектные файлы стали такими, которые могут быть установлены операционной системой. Введите единое целое исполнения, то есть исполняемую программу. В соответствии с методом связывания библиотечной функции, указанным разработчиком, обработку ссылок можно разделить на два типа:
1. Статическая ссылка: все функции компилируются в программу во время компиляции.
2. Динамическая ссылка: операционная система помогает переносить динамическую библиотеку в область памяти при запуске программы.
Для вызовов функций в исполняемых файлах можно использовать динамическое связывание или статическое связывание соответственно. Использование динамического связывания может сделать конечный исполняемый файл короче и сэкономить некоторую память, когда общий объект используется несколькими процессами, потому что в памяти должна храниться только одна копия кода общего объекта. Но дело не в том, что использование динамического связывания обязательно лучше статического связывания. В некоторых случаях динамическое связывание может привести к некоторому снижению производительности.

5. Динамические и статические библиотеки

Как под Windows, так и под Linux имеется большое количество библиотек. Что такое библиотеки? По сути, библиотека - это двоичная форма исполняемого кода, который может быть загружен в память и выполнен операционной системой. Обычно мы пишем некоторые функции общего назначения в виде библиотек функций, поэтому библиотека написана другим, существующим, зрелым и повторно используемым кодом. Вы можете использовать ее, но вы должны соблюдать лицензионное соглашение. В нашем реальном процессе разработки невозможно написать каждый фрагмент кода с нуля. Когда у нас есть библиотека, мы можем напрямую связать нужные нам файлы с нашей программой. Это может сэкономить нам много времени и повысить эффективность разработки. В Linux есть два типа библиотек: статические библиотеки и динамические библиотеки. Сходство между этими двумя библиотеками заключается в том, что обе библиотеки создаются из файлов .o, Давайте обсудим их различия ниже:
1. Статическая библиотека: файл статической библиотеки назван в честь «libxxx.a», «xxx» - это имя библиотеки, а «lib» добавляется впереди, чтобы указать, что это библиотека, как в Windows, так и в Linux. Суффикс «.a» указывает на статическую библиотеку. Код статической библиотеки загружается в программу во время процесса компиляции, что приводит к большой файловой памяти после компиляции.Метод связывания статической библиотеки заключается в том, что исполняемый файл, созданный после компиляции, не нуждается в поддержке внешней библиотеки функций. Если статическая библиотека обновляется, программу необходимо повторно перевести.
2. Динамическая библиотека: имя динамической библиотеки похоже на статическую библиотеку. Оно начинается с «lib», что указывает на то, что это библиотека. Суффикс-имя в Linux - «.so (общий объект)», то есть «libXXX». .так". В Windows используется суффикс «.dll (библиотека динамической компоновки)», то есть «libXXX.dll». При компиляции динамическая библиотека не компилируется в целевой код. Вместо этого соответствующая функция в библиотеке функций вызывается, когда ваша программа выполняется для соответствующей функции. Недостатком этого является то, что функция библиотеки не интегрирована в программу. , Значит, в операционной среде программы должна быть соответствующая библиотека. Преимущество состоит в том, что изменение динамической библиотеки не влияет на вашу программу, поэтому обновление динамической библиотеки более удобно.
Между ними также есть очевидные различия: когда одна и та же программа использует статические библиотеки и динамические библиотеки для создания двух исполняемых файлов, файлы, созданные статическим связыванием Занятая память намного больше, чем файлы, созданные при динамической компоновке. Это связано с тем, что статическая компоновка компилирует все функции в программу во время компиляции, в то время как динамическая компоновка использует операционную систему, чтобы помочь перенести динамическую библиотеку в пространство памяти во время работы программы. Кроме того, если динамическая библиотека и статическая библиотека существуют одновременно, компоновщик предпочтительно использует динамическую библиотеку.

6. Общие параметры компиляции gcc

Параметры Описание
-E Только предварительная обработка, а не компиляция
-S Только компилировать, а не собирать
-c Только компилировать, собирать, а не связывать
-g Скомпилированный исполняемый файл содержит отладочную информацию gdb, которая может быть отлажена с помощью gdb.
-o Укажите имя файла скомпилированного исполняемого файла
-l Укажите каталог поиска для включаемых файлов
-L Укажите путь к библиотеке (динамической или статической), необходимой для компоновки
-ansi Стандарт ANSI
-std=c99 Стандарт C99
-Werror Не различать предупреждения и ошибки и прекращать компиляцию при обнаружении любого предупреждения
-Wall Включите большинство предупреждений
–static Статическая компиляция (по умолчанию - динамическая компиляция)
-static Статическая ссылка (по умолчанию статическая ссылка)

1. Запись в несколько файлов

Если мы хотим скомпилировать несколько файлов, нам сначала нужно записать файл заголовка и файл .c функции-функции, а затем вызвать функцию-функцию в основной функции. Вот как это записать. Взгляните на пример.

①Функция функция .c файл

Во-первых, вам нужно включить свой собственный файл заголовка, чтобы завершить определение функции, вам нужно только объявить в файле заголовка, давайте посмотрим, как написать файл заголовка.

②Файл заголовка функции

③Записан основной функциональный файл

В основной функции мы можем вызывать написанную функцию по мере необходимости, но следует отметить, что в проекте может быть только одна основная функция.

2. Скомпилируйте несколько файлов отдельно

Наша многофайловая компиляция не может напрямую использовать gcc для компиляции каждого файла, но сначала генерирует файлы сборки с помощью gcc -c (только компилировать, собирать, а не связывать), а затем генерировать исполняемые файлы с помощью gcc вместе со всеми файлами сборки. Наконец, удалите файлы .o в этом процессе.


3. Компиляция сценария оболочки

Компиляция каждого файла по отдельности - слишком большая проблема. Нам нужен одноэтапный метод компиляции. Здесь мы можем использовать сценарии оболочки.


4. makefile

Что такое make-файл? Может быть, многие программисты Windows этого не знают, потому что эти Windows IDE делают эту работу за вас. Чтобы компилировать программное обеспечение под Unix, вы должны сами написать make-файлы, и то, можете ли вы писать make-файлы, показывает с одной стороны, есть ли у человека возможность выполнять крупномасштабные проекты. Потому что make-файл связан с правилами компиляции всего проекта. Исходные файлы в проекте не учитываются. Они размещаются в нескольких каталогах в соответствии с типом, функцией и модулем. Makefile определяет ряд правил, чтобы указать, какие файлы нужно скомпилировать в первую очередь, какие файлы нужно скомпилировать позже, а какие файлы нужно перестроить. Компилировать и даже выполнять более сложные функциональные операции, потому что make-файл похож на сценарий оболочки, в котором также могут выполняться команды операционной системы. Преимущество make-файла заключается в «автоматической компиляции». После его написания требуется только одна команда make, и весь проект полностью автоматически компилируется, что значительно повышает эффективность разработки программного обеспечения. Make - это командный инструмент, который объясняет инструкции в make-файле. Вообще говоря, в большинстве IDE есть эта команда, например make в Delphi, nmake в Visual C ++ и make в GNU под Linux. Видно, что makefile превратился в метод компиляции в инженерии.

Выше приведен базовый синтаксис make-файла, неважно, если вы его не понимаете, давайте напишем простой пример, чтобы понять его глубже.



С помощью make-файла наша рабочая нагрузка может быть значительно уменьшена. Если в приведенном выше содержании есть какие-либо ошибки, пожалуйста, исправьте меня!

Я только что унаследовал некоторый код C ++, который был написан плохо с одним файлом cpp, который содержал основную и кучу других функций. Есть также .h файлы, которые содержат классы и определения их функций.

До сих пор программа компилировалась с помощью команды g++ main.cpp . Теперь, когда я разделил классы .h и .cpp файлы, мне нужно использовать make-файл или я все еще могу использовать g++ main.cpp команду?

перечислите все остальные файлы cpp после main.cpp.

Или вы можете собрать их все по отдельности. Затем вы связываете все полученные ".o" файлы вместе.

Это в любом случае плохая практика? Я хотел бы использовать это в моем make-файле. @gabriel_vincent, это не обязательно плохая практика, но это будет означать, что редактирование одного файла в сотнях проектов приведет к тому, что компилятор переделает всю работу для всех файлов. Компиляция отдельно позволяет инкрементную компиляцию. @gabriel_vincent Для начала не нужно писать make-файлы вручную. Вместо этого используйте правильную систему сборки, такую ​​как CMake. @BaummitAugen Да, за исключением того, что я просто хочу скомпилировать эту крошечную 2-файловую программу, которую я написал за 14 минут, и я действительно предпочел бы потратить 1 минуту на написание make-файла, а не час на настройку cmake.

Чтобы скомпилировать отдельно без ссылок, вам нужно добавить -c опцию:

Обратите внимание, если вы хотите контролировать имя исполняемого файла на шаге компоновки, просто делайте то, что вы обычно делаете: g++ -o my_executable myclass.o main.o

Теперь, когда я разделил классы на файлы .h и .cpp, мне нужно использовать make-файл или я все еще могу использовать команду "g ++ main.cpp"?

Компиляция нескольких файлов одновременно - плохой выбор, если вы собираетесь поместить это в Makefile.

Обычно в Makefile (для GNU / Make ) достаточно написать:

Этот способ make будет правильно перекомпилировать только то, что нужно перекомпилировать. Можно также добавить несколько настроек для генерации зависимостей файла заголовка - так, чтобы make также правильно перестраивал то, что нужно перестраивать из-за изменений файла заголовка.

Читайте также: