Создание файла библиотеки в makefile и компиляция после этого

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

В любом случае, я использую библиотеку petsc и make-файл, который они предоставили:

CFLAGS          = 
FFLAGS          = 
CPPFLAGS        = 
FPPFLAGS        =
LOCDIR          = /home/user/.../.../   # Working folder
EXAMPLESC       = main.cpp class.cpp        #.cpp file names here
EXAMPLESF       =
#MANSEC          = Mat I don't know what this is but it seems to work without it.

include ${PETSC_DIR}/conf/variables
include ${PETSC_DIR}/conf/rules

myProgram: main.o class.o  chkopts
    -${CLINKER}  -o myProgram main.o class.o ${PETSC_MAT_LIB}
    ${RM} main.o class.o

include ${PETSC_DIR}/conf/test

ARFLAGS будет -rv по умолчанию, поэтому где я должен предоставить такую ​​​​информацию, как

ar -rv libclassdll.a class.o

и где я должен добавить -L./-lclassdll?

Я новичок в создании make-файлов, поэтому я немного заблудился здесь :‹

Я попытался изменить строку на

myProgram: main.o class.o  chkopts
    -${CLINKER}  -o myProgram main.o class.o ${AR} libclassdll.a class.o ${PETSC_MAT_LIB}
    ${RM} main.o class.o

а затем моя команда компиляции выглядит так: mpicxx -o myProgram main.o class.o /usr/bin/ar/ libclassdll.a class.o -L (здесь много ссылок) и, по крайней мере, там написано: g++ classdll.a нет такого файла или каталога.

Так что он не генерирует даже файл lib для меня. Так что любые идеи будут действительно оценены.

Новая проблема, когда я загрузил make-файл на другую машину, мой текущий make-файл выглядит так

LibMyClass.so: MyClass.o  chkopts
    -${CLINKER}  -shared -Wl,-soname,${SONAME} -o ${VERS}   *.o  ${PETSC_MAT_LIB}

    mv ${VERS} ${LIBADD}
    ln -sf ${LIBADD}${VERS} ${LIBADD}${SOWOV}
    ln -sf ${LIBADD}${VERS} ${LIBADD}${SONAME}

Это работает на одной машине, но другая машина выдает следующую ошибку

/usr/bin/ld: MyClass.o: relocation R_X86_64_32S against `.rodata' can not be used when making a shared object; recompile with -fPIC
MyClass.o: could not read symbols: Bad value

Конечно, я изменил пути, но думаю, это указывает на проблему другого типа, потому что даже если я наберу «g++ -shared -Wl,-soname,libmyclass.so.1 -o libmyclass.so.1.0 MyClass.o» или «g++ -fPIC -share..." Я получу ту же ошибку.


person Mare    schedule 06.03.2012    source источник
comment
Разве ${AR} не должен стоять в самом начале строки? В конце концов, это приказ, не так ли?   -  person celtschk    schedule 07.03.2012
comment
Вы уже включили class.o среди объектных файлов, связанных для создания исполняемого файла программы, поэтому бессмысленно/избыточно также связывать библиотеку, созданную из class.o.   -  person Kaz    schedule 07.03.2012
comment
Если бы вы уже построили библиотеку с помощью ar и скомпилировали main.o, какую команду вы бы использовали, чтобы связать их вместе и собрать myProgram?   -  person Beta    schedule 07.03.2012
comment
Не удаляйте свои объектные файлы в правиле, которое связывает программу. Это глупо и в значительной степени сводит на нет смысл использования make. Make — это инструмент, который выполняет инкрементную перестройку вашей программы на основе правил. Если вы сбрасываете промежуточные объектные файлы каждый раз при сборке, вы можете просто построить с помощью скрипта. Или просто подходит тип cc *.c -o myprogram.   -  person Kaz    schedule 07.03.2012
comment
Привет, Каз, буду иметь в виду, спасибо!   -  person Mare    schedule 07.03.2012


Ответы (2)


В идеале вы должны сначала создать библиотеку, а затем использовать ее, как если бы вы делали это «вручную».

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

libclassdll.a: class.o
    ar -rv libclassdll.a class.o

Или, более кратко, вот так:

libclassdll.a: class.o
    ar $(ARFLAGS) $@ $^

Тогда правило для myProgram становится таким:

# Assuming CLINKER is something civilized, like gcc
myProgram: main.o libclassdll.a  chkopts
    -${CLINKER} -o myProgram main.o -L. -lclassdll ${PETSC_MAT_LIB}

или лучше:

myProgram: main.o libclassdll.a  chkopts
    -${CLINKER} -o $@ $< -L. -lclassdll ${PETSC_MAT_LIB}

Итак, в вашем make-файле вы должны заменить

myProgram: main.o class.o  chkopts
    -${CLINKER}  -o myProgram main.o class.o ${PETSC_MAT_LIB}
    ${RM} main.o class.o

с

myProgram: main.o libclassdll.a  chkopts
    -${CLINKER} -o $@ $< -L. -lclassdll ${PETSC_MAT_LIB}

libclassdll.a: class.o
    ar $(ARFLAGS) $@ $^

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

person Beta    schedule 06.03.2012
comment
По какой-то причине я все еще получаю следующую ошибку при компиляции: неопределенная ссылка на MyClass::Class::Function()... Я искал много способов использовать функции вне библиотеки, и теперь я следую msdn.microsoft.com/en-us/library/ms235627.aspx, чтобы все еще что-то не так с моей ссылкой? - person Mare; 08.03.2012
comment
или мне как-то создать dll, как здесь msdn.microsoft.com/en-us/ библиотека/ms235636.aspx ? - person Mare; 08.03.2012
comment
Итак, когда вы компилируете и связываете вручную, ошибки нет, но когда вы используете make-файл, вы получаете эту ошибку, верно? Если да, то посмотрите на четыре цели: 1) main.o, 2) class.o, 2) библиотека, 3) myProgram. Попробуйте построить что-то вручную, что-то с помощью Make, найдите ответственных и расскажите нам о результатах... - person Beta; 08.03.2012
comment
На самом деле даже при компиляции вручную возникает ошибка с линковкой. Я предполагаю, что, возможно, мне следует использовать .so вместо .a, но, к сожалению, мне нужно идти сейчас. Я вернусь к этому вопросу позже. Я просто тестировал этот пример msdn dll с www.gamedev.net/topic/327323-how-to-create-and-use-a-dll-with-c-/ и все равно получил ошибку связывания:/ - person Mare; 08.03.2012
comment
На самом деле я просто следовал инструкциям dll yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html отсюда, и теперь все работает! Но у меня есть новая проблема, которую я обновил до первого поста, когда перенес makefile на другой компьютер. - person Mare; 09.03.2012

Заставьте myProgram зависеть от main.o и от libclass.a (не называйте его libclassdll.a; это не DLL, а статическая библиотека).

Общий смысл решения:

# $@ means "the target of the rule"
# $^ means "the prerequisites: main.o and libclass.a"

myProgram: main.o libclass.a
        $(CC) -o $@ $^ # additional arguments for other libraries, not built in this make

libclass.a: class.o
        # your $(AR) command goes here to make the library
person Kaz    schedule 06.03.2012
comment
Благодарю за разъяснение. - person Mare; 07.03.2012
comment
@kaz, спасибо. Как вы изменили выходной каталог ar? Я хочу переместить все файлы в каталог сборки. gcc имеет переключатель -o, но ar, похоже, не имеет никаких переключателей для этого - person Rika; 08.04.2020
comment
@Rika ar принимает имя файла архива в качестве первого аргумента, не являющегося параметром, поэтому для него не требуется параметр -o. В приведенном выше Makefile имя архива фиксируется как имя цели libclass.a. В правиле libclass.a на него будет ссылаться $@, который будет передан $(AR) в качестве первого аргумента, не являющегося параметром. Чтобы изменить его местоположение, мы переименуем цель. make должен быть в курсе, где что находится; мы не хотим перемещать выходные файлы за спиной make. - person Kaz; 08.04.2020
comment
Большое спасибо, очень ценю это :). Я сам сделал что-то вроде этого: libcore.a: Core.o ar rcsv libcore.a $(BUILD_DIR)/Core.o && mv ./libcore.a $(BUILD_DIR) он связывается, а затем перемещается в build_dir. - person Rika; 08.04.2020
comment
@Rika Проблема в том, что правило больше не обновляет цель libcore.a, которую оно обещает сделать. Это фактически фальшивая цель; вы можете пометить его .PHONY (и, возможно, дать ему более простое имя, например libcore). Когда цель фальшивая, make не проверяет ее существование в виде файла. - person Kaz; 08.04.2020
comment
@Rika Кроме того, если целью правила является наличие $(BUILD_DIR)/libcore.a, то почему бы вам не сделать этот путь целью правила, а также обязательным условием для других правил, которые связаны с этой библиотекой? Более того, если Core.o на самом деле $(BUILD_DIR)/Core.o, то строка пререквизитов также лжет, если только VPATH не используется для поиска пререквизитов в нескольких каталогах. - person Kaz; 08.04.2020
comment
@Kaz: Большое спасибо. действительно ценю это. на самом деле я только что начал Makefile, и я действительно мало что знаю об этом. Я подумал, что это хороший выбор, так как компиляция была в порядке! кажется, что нет! Я буду менять их соответственно тогда. большое спасибо :) - person Rika; 09.04.2020
comment
@Kaz, кажется, на этот раз я все сделал правильно: pastebin.com/tt41BBax - person Rika; 09.04.2020
comment
@Rika На первый взгляд это выглядит хорошо. В большом проекте с большим количеством .o файлов мы обычно делаем что-то вроде OBJS := $(addprefix $(BUILD_DIR),foo.o bar.o parser.o lexer.o ...), чтобы уменьшить распространение $(BUILD_DIR)/. - person Kaz; 09.04.2020
comment
@Rika Вместо -c $(CORE_CPP) -o $(BUILD_DIR)/Core-dll.o вы можете использовать целевые автоматические переменные -c -o $@ $^. $^ расширяется до всех предпосылок правила, а $@ до цели. - person Kaz; 09.04.2020
comment
Большое спасибо, не могли бы вы указать мне где-нибудь, где я могу прочитать больше об этом? Я очень ценю вашу любезную помощь :) - person Rika; 09.04.2020