Компиляция

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

make

Общество свободного программного обеспечения считает утилиту make излюбленным инструментом для компиляции исходных кодов. Это дает следующие преимущества:

  • Разработчик экономит время, потому что у него есть возможность эффективно управлять процессом компиляции своего проекта.

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

Действия, которые необходимо выполнить для получения откомпилированной версии исходных кодов, обычно хранятся в файле с названием Makefile или (реже) в файле GNUMakefile. На самом деле, при вызове команды make читается этот файл из текущего каталога. Возможно явное указание этого файла для команды make с помощью опции -f.

Правила

Программа make действует согласно системным зависимостям (dependencies), так для компиляции бинарного файла (“ цели (target) ”) требуется прохождение через несколько стадий (“зависимостей (dependencies)”). Например, для того чтобы создать (мнимый) бинарный файл glloq, сначала нужно откомпилировать объектные файлы main.o и init.o (это промежуточные файлы в процессе компиляции), а потом их нужно слинковать в готовый бинарный файл. Эти объектные файлы также являются целями, а зависимостями для них будут файлы исходных текстов.

Этот текст является только маленьким введением, инструкцией по выживанию в сложном мире make. Для того, чтобы узнать больше, мы советуем вам отправится на сайт APRIL, где размещена более подробная документация о make. [31] Для получения исчерпывающей информации обратитесь ко второму изданию O'Reilly Managing Projects with Make Andrew Oram и Steve Talbott.

Поехали!

Обычно при использовании программы make придерживаются некоторых соглашений. Например, таких как:

  • make без аргументов производит просто компиляцию и не выполняет установки программы.

  • make install компилирует программу (правда не всегда), и инсталлирует необходимые файлы в нужное место в файловой системе. Некоторые файлы не всегда корректно инсталлируются (man, info), но их можно скопировать вручную. Иногда команду make install необходимо запускать несколько раз в подкаталогах. Обычно это случается с модулями, разработанными третьими лицами.

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

На первой стадии необходимо скомпилировать программу, для этого нужно набрать: (нереальный пример):

$ make
gcc -c glloq.c -o glloq.o
gcc -c init.c -o init.o
gcc -c main.c -o main.o
gcc -lgtk -lgdk -lglib -lXext -lX11 -lm glloq.o init.o main.o -o glloq

Замечательно, допустим что все бинарники правильно откомпилировались. Мы готовы для перехода на следующую стадию, на которой будут инсталлироваться файлы пакета (бинарные файлы, файлы с данными и т.д). Смотрите раздел “Инсталляция”.

Объяснения

Если вы достаточно любопытны, чтобы заглянуть в файл Makefile, то вы найдете там известные команды (rm, mv, cp, и т.д.) и, кроме того, странные строки вроде этой $(CFLAGS).

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

Например, для того чтобы напечатать строку “ foo ” при выполнении цели make all, можно сделать следующее:

TEST = foo
all:
        echo $(TEST)

Обычно определены следующие переменные:

  1. CC: Это компилятор. Обычно это cc, который присутствует в большинстве свободных систем, также это может быть его аналог gcc. Если у вас возникают сомнения, ставьте gcc.

  2. LD: это программа, которая используется на конечной стадии компилирования (см. раздел “Четыре шага компиляции”). По умолчанию это программа ld.

  3. CFLAGS: это дополнительные опции компилятору, которые используются компилятором на первой стадии компиляции. Среди них:

    • -I<path>: указывает компилятору где искать дополнительные заголовочные файлы (к примеру: -I/usr/X11R6/include разрешает компилятору использовать файлы header, расположенные в allows /usr/X11R6/include).

    • -D<symbol>: определяет дополнительные символы, которые могут быть необходимы для программ, компиляция которых зависит от определения таких символов (к примеру: использовать заголовочный файл string.h в случае, если определено HAVE_STRING_H).

    Строка для компиляции обычно выглядит следующим образом:

    $(CC) $(CFLAGS) -c foo.c -o foo.o
    
  4. LDFLAGS (или LFLAGS): Этот аргумент используется во время конечной стадии компиляции. Среди них:

    • -L<path>: Определяет дополнительные пути поиска библиотек (например: -L/usr/X11R6/lib).

    • -l<library>: Определяет дополнительные библиотеки, которые будут использоваться в конечном этапе компиляции.

А что если... все это не работает?

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

  1. glloq.c:16: decl.h: No such file or directory

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

    • Проверьте, действительно ли существует данный файл в следующих каталогах: /usr/include, /usr/local/include, /usr/X11R6/include или в каком-нибудь из подкаталогов. Если там нет, поищите по всему диску (с помощью утилит find или locate) и, если вы все же не можете найти этот файл, проверьте, действительно ли вы установили библиотеку, в которую входит этот заголовочный файл. Примеры использования утилит find и locate вы можете найти в соответствующих страничках руководства (man find; man locate).

    • Проверьте, действительно ли этот файл доступен для чтения (для проверки этого введите less <path>/<file>.h )

    • Если это каталог типа /usr/local/include или /usr/X11R6/include, вам прийдется добавить новый аргумент компилятору. Откройте соответствующий Makefile (будьте внимательны: нужный файл находится в каталоге, в котором произошла ошибка компиляции [32] ) в вашем любимом текстовом редакторе (Emacs, Vi, и т.д.). Перейдите на строку, в которой содержится ошибка, и добавьте строку -I<path> - где <path> это путь к каталогу, в котором вы отыскали недостающий заголовочный файл. Эти опции нужно добавить в конце строки, в которой вызывается компилятор (gcc, или $(CC)). Если вы не знаете куда добавить эти опции, допишите их в конце строк CFLAGS=<something> или CC=<something>, которые расположены в начале файла.

    • Запустите снова make и, если это опять не работает, перепроверьте снова то, что эти опции (смотрите предыдущий пункт) действительно были добавлены и получены компилятором.

    • Если это опять не работает, обращаетесь за помощью к вашему местному гуру, или к сообществу свободного программного обеспечения (смотрите раздел “Техническая поддержка”).

  2. glloq.c:28: `struct foo' undeclared (first use this function)

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

    • Попробуйте найти где определяется эта самая структура (в программе или ее определяет система). Для этого используется утилита grep, с помощью которой выясняется определена ли эта структура в каком либо заголовочном файле.

      Станьте root-ом и выполните следующую команду:

      $ find . -name '*.h'| xargs grep 'struct foo' | less
      

      В результате может получиться очень много строк (потому что вы найдете все случаи, когда эта структура используется). Если структура все-таки существует, найдите заголовочный файл, в котором она определяется.

      Определение структуры выглядит так:

      struct foo {
      			     <содержимое структуры>
      };
      

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

      • в начало .c файла, содержащего ошибку, добавьте строку #include "<filename>.h".

      • скопируйте определение этой структуры в начало .c файла (на самом деле это не очень правильно, зато обычно помогает).

    • Если файл с определением находится в одном из системных каталогов /usr/include, /usr/X11R6/include, или /usr/local/include) , то сделайте тоже самое, только в этом случае вставьте строку такого вида #include <<filename>.h>.

    • Если эта структура не находится, попробуйте выяснить в какой библиотеке (то есть это набор функций, структур и т.д., содержащихся в отдельном пакете) оно должно содержатся (просмотрите файлы INSTALL или README на предмет того, какие библиотеки использует данная программа и какие версии библиотек необходимы). Если требуемые программой версии библиотек не соответствуют тем, что установлены в вашей системе - вам прийдется установить требуемые версии этих библиотек.

    • Если все же это не работает, уточните, может ли работать эта программа в Linux (некоторые программы могут не работать корректно во всех UNIX). Проверьте также, правильно ли переданы все опции команде configure. Особенно, нет ли каких-то дополнительных опций для вашей конкретной архитектуры.

  3. Ошибки синтаксического анализа (parse error)

    Такие проблемы довольно сложно решать, так как компилятор может выдать сообщение об ошибке в строке, которая находится ниже той строки, в которой реально присутствует ошибка. Иногда это просто неопределенный тип данных. Если вы встречаете сообщение об ошибке такого вида:

    main.c:1: parse error before `glloq_t
    main.c:1: warning: data definition has no type or storage class
    

    это значит, что тип данных glloq_t не определен. Для решения этой проблемы нужно предпринять действия, аналогичные тем, что были описаны для решения предыдущей проблемы.

    Замечание

    еще может быть parse error в старых библиотеках curses, если мне не изменяет память.

  4. no space left on device (на диске кончилось место)

    Эту проблему легко решить: недостаточно места на диске для того, чтобы создать бинарник из исходника. Решение состоит в расчистке места на том разделе, на котором находится каталог инсталляции (удалите временные файлы или исходники, деинсталлируйте программы, которые вы не используете). Если вы развернули его в /tmp, а не в /usr/local/src, это зря, потому что он напрасно занимает место на разделе /tmp. Проверьте, нет ли на диске файлов core>. Если найдутся, удаляйте их или заставьте их удалиться, если они принадлежат другому пользователю.

  5. /usr/bin/ld: cannot open -lglloq: No such file or directory

    Это означает, что программа ld (используемая gcc во время последнего шага компиляции) не может найти библиотеку. Для того чтобы ее включить, ld ищет файл, чье имя является аргументом типа -l<library>. Это файл lib<library>.so. Если ld не находит его, получается ошибка. Для решения проблемы делайте следующее:

    1. Проверьте, есть ли файл на диске с помощью команды locate. Графические библиотеки обычно находятся в /usr/X11R6/lib. Например:

      $ locate libglloq
      

      Если поиск ничего не принес, вы можете попытаться поискать с помощью команды find command (то есть: find /usr -name libglloq.so*). Если и это ничего не дало, вам прийдется установить его.

    2. Как только библиотека будет размещена, проверьте ее на доступность для ld: файл /etc/ld.so.conf определяет, где искать библиотеки. Добавьте каталог-виновник в его конец (возможно, вам прийдется перегрузить компьютер, чтобы изменения вступили в силу). Кроме того, вы можете добавить этот каталог путем изменения содержимого переменной окружения LD_LIBRARY_PATH. Например, если каталог такой /usr/X11R6/lib, напишите:

      export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/X11R6/lib

      (если ваша shell это bash).

    3. Если до сих пор не работает, убедитесь что формат библиотеки это выполняемый файл (или ELF) командой file. Если он является символической ссылкой, проверьте что ссылка правильная и не указывает на несуществующий файл (например, так nm libglloq.so). Права файла тоже могут быть неверными (если вы используете аккаунт, отличный от root, и если библиотека защищена от чтения, например).

  6. glloq.c(.text+0x34): undefined reference to `glloq_init'

    Это проблема с символом, которая не была решена во время последнего шага компиляции. Обычно это проблема библиотеки. Может возникать по нескольким причинам:

    • первое, что необходимо выяснить, это предполагалось ли наличие символа в библиотеке. Например, если символ в начале это gtk, он принадлежит библиотеке gtk. Если имя библиотеки легко определимо, (frobnicate_foobar), вы можете вывести список символов библиотеки командой nm. Например,

      $ nm libglloq.so
      0000000000109df0 d glloq_message_func
      000000000010a984 b glloq_msg
      0000000000008a58 t glloq_nearest_pow
      0000000000109dd8 d glloq_free_list
      0000000000109cf8 d glloq_mem_chunk
      

      Добавив параметр -o к nm, вы получите вывод имени библиотеки в каждой строке, что облегчит поиск. Давайте предположим, что мы ищем символ bulgroz_max, сырое решение поиска выглядит так:

      $ nm /usr/lib/lib*.so | grep bulgroz_max
      $ nm /usr/X11R6/lib/lib*.so | grep bulgroz_max
      $ nm /usr/local/lib/lib*.so | grep bulgroz_max
      /usr/local/lib/libfrobnicate.so:000000000004d848 T bulgroz_max
      

      Замечательно! Символ bulgroz_max определен в библиотеке frobnicate (большая буква T стоит перед ее именем). Теперь вам только нужно добавить строку -lfrobnicate в строку компиляции, отредактировав файл Makefile : добавьте ее в конец строки, где определены LDFLAGS или LFGLAGS (или, на худой конец, CC) , или в строку, соответствующую созданию конечного бинарного файла.

    • компиляция производится с версией библиотеки, которая не подходит для данного программного обеспечения. Читайте README или INSTALL чтобы узнать, какая версия должна использоваться.

    • не все объектные файлы поставки были корректно слинкованы. Файл, в котором определена функция, отсутствует. Напишите nm -o *.o чтобы узнать что это за файл и добавить соответствующий файл .o в строку компиляции, если его не хватает.

    • проблемная функция или переменная может не существовать. Попробуйте ее удалить: отредактируйте проблемный файл (его имя указано в сообщении об ошибке). Это довольно отчаянное решение, которое может привести к неуправляемому выполнению программы (segfault при запуске, и т.д.).

  7. Segmentation fault (core dumped)

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

     

     

  8. no space on /tmp

    Компиляции необходимо временное рабочее пространство во время ее различных шагов; если ей не хватит места на диске, она упадет. Поэтому вы можете почистить свои разделы диска, но будьте осторожны с некоторыми программами, которые выполняются (X, сервер, каналы и т.д.), так как они могут упасть, если некоторые файлы будут удалены. Вы должны знать что делаете! Если раздел /tmp является частью раздела, который содержит не только его (например, root), поищите и, по возможности, удалите несколько core файлов.

  9. make/configure в бесконечном рекурсивном цикле

    Часто это проблема со временем в вашей системе. Действительно, make нужно знать дату в компьютере и дату файлов для проверки. Она сравнивает даты и использует результат для того, чтобы определить насколько цель отличается по времени создания от зависимостей.

    Проблемы с датой могут заставить make бесконечно пересоздавать саму себя (или формировать снова и снова поддерево в бесконечном цикле рекурсии). В таком случае проблема решается обычно использованием команды touch (которая здесь используется для установки файлам по запросу текущего времени).

    Например:

    $ touch *
    

    или так (грубо, но эффективно):

    $ find . | xargs touch
    


[31] На русском языке информацию о make можно получить тут: Эффективное использование GNU Make , Применение GNU make , GNU Automake

[32] Проанализируйте сообщения об ошибках, выдаваемые программой make. Обычно в последних строках содержится название каталога, в котором произошла ошибка (сообщение имеет примерно такой вид make[1]: Leaving directory `/home/benj/Project/foo'). Выберите сообщение с самым маленьким номером. Для проверки того, что это именно тот каталог, зайдите в него и повторно выполните make. При этом вы должны получить точно такую-же ошибку.