Как связать libs только один раз в GCC? - PullRequest
0 голосов
/ 15 мая 2019

Простите за мой вопрос, я новичок в GCC.У меня есть рамочный проект, который содержит исходный код для нескольких подкомпонентов.

Структура ниже:

Framework/
makefile //Master makefile in root
    Component1/
       src/
       bin/
       makefile
    Component2/
       src/
       bin/
       makefile
    ...
    ...
    ...
    ComponentN/
       src/
       bin/
       makefile

Теперь каждый make-файл в ComponentN / каждого из каталогов скомпилирует код в своем соответствующем src / и выведет .o в каталог bin /.

Корневой make-файл, однако, рекурсивно ищет все файлы .o и связывает их все в один исполняемый файл с именем 'framework'

Проблема:

Для зависимостей кода, таких как glib, gdbus, gio Я должен связать их один раз при создании объектов .o в каждом из проектов компонентов.

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

Почему я должен сделать это дважды?Я заинтересован в понимании внутренней механики.

В соответствии с запросом, я добавляю make-файл отдельных компонентов, которые содержат файлы * .o

CC = gcc
CFLAGS = -g3
LIBS = `pkg-config --cflags --libs glib-2.0`
BINDIR = bin
OUTOBJ = $(addprefix $(BINDIR)/, objex.o)

$(BINDIR)/%.o : %.c
               $(CC) -c $< $(CFLAGS) -o $@ $(LIBS)

all: $(OUTOBJ)

$(OUTOBJ): | $(BINDIR)

$(BINDIR):
          mkdir $(BINDIR)

.PHONY: clean
clean:
      rm bin/*


1 Ответ

2 голосов
/ 15 мая 2019

Объектные файлы (.o) создаются командами компиляции, например,

gcc -c -o foo.o foo.c ...
g++ -c -o baz.o baz.cpp ...

-c означает compile; не связывайте . При создании объектные файлы компилятором. Любые параметры связи, которые вы добавляете в компиляцию команда, например

gcc -c -o foo.o foo.c -L/my/libs -lbar -lgum

просто игнорируются.

Параметры связывания активируются командой связывания, которая создает программу или общую / динамическую. библиотека, связывая вместе объектные файлы и библиотеки, например

gcc -o prog foo.o baz.o -L/my/libs -lbar -lgum
gcc -shared -o libfoobaz.so foo.o baz.o -L/my/libs -lbar -lgum

Итак:

Для зависимостей кода, таких как glib, gdbus, gio, я должен связать их один раз при создании объектов .o в каждом из проектов компонентов.

Нет, нет, и вы не можете.

Позже

С учетом проблемы makefile вполне понятно, как устранить $(LIBS) справка из рецепта компиляции и то, что вам мешало. Makefile определяет:

LIBS = `pkg-config --cflags --libs glib-2.0`

что является ошибкой. $(LIBS) расширяется до стандартного выхода Команда:

pkg-config --cflags --libs glib-2.0

, представляющая собой единственную строку, содержащую оба обязательных параметра для компиляции исходного кода, который #include -s glib-2.0 API (за счет --cflags) а также опции связывания , необходимые для связывания программы или общей библиотеки против libglib-2.0 (из-за --libs). В моей системе это:

$ pkg-config --cflags --libs glib-2.0
-I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -lglib-2.0

из которых только параметры компиляции будут выводиться с помощью:

$ pkg-config --cflags glib-2.0
-I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include

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

$ pkg-config --libs glib-2.0
-lglib-2.0

Но поскольку оба набора параметров доступны только вместе через расширение из $(LIBS) вы не можете успешно скомпилировать без передачи опция связывания -lglib-2.0, которая является избыточной и игнорируется.

Поскольку ваш make-инструмент, очевидно, является GNU Make, make-файл (кстати, неплохой!) Лучше записать как:

Makefile

CC := gcc
CFLAGS := -g3 $(shell pkg-config --cflags glib-2.0)
BINDIR := bin
SRCS := objex.c
OUTOBJ := $(addprefix $(BINDIR)/, $(SRCS:.c=.o))

.PHONY: all clean

all: $(OUTOBJ)

$(BINDIR)/%.o : %.c
    $(CC) -c $< $(CFLAGS) -o $@

$(OUTOBJ): | $(BINDIR)

$(BINDIR):
    mkdir -p $(BINDIR)

clean:
    $(RM) $(OUTOBJ)

, который обходится без LIBS и работает с нуля, как:

$ make
mkdir -p bin
gcc -c objex.c -g3 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -o bin/objex.o

Обратите внимание на несколько других улучшений: -

Использование немедленного расширения (:=), где это применимо, вместо ненужного рекурсивное расширение (=). См. 6.2 Два варианта переменных

Использование прямой подстановки оболочки make - $(shell command) - в предпочтении к расширению backtick в рецепт исполнения. См. 8.13 Функция оболочки .

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

С вашим clean рецептом:

clean:
      rm bin/*

make clean потерпит неудачу, если когда-либо будет запущен, кроме как после успешной сборки Рецепт заменяется на $(RM) $(OUTOBJ), используя предопределенный макрос удаления GNU Make, который не подведет.

Наконец, помните, что ваш рецепт рецепта, где бы он ни находился, * требует библиотечные опции для glib-2.0, который вы должны указать в его make-файле:

LIBS := $(shell pkg-config --libs glib-2.0) # ...and any more library options required

для использования в рецепте, подобном:

prog: $(OBJS)
    $(CC) -o $@ $(LDFLAGS) $^ $(LIBS)

[1] Строго говоря, параметры препроцессора должны появляться в определении CPPFLAGS (Флаги препроцессора C), не путать с CXXFLAGS (опции компиляции C ++).

[2] Строго говоря, параметры определения, отличные от библиотек, должны появляться в определении LDFLAGS.

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