Могу ли я скомпилировать динамическую библиотеку в Linux и связать ее в Windows?

Я использую Linux (в частности, Ubuntu 20.04) и хотел бы знать, есть ли способ создать динамическую библиотеку, которую можно было бы связать с машиной Windows. Я использую GNU make и кросс-компилятор mingw, чтобы попытаться сделать это.

Вот простой make-файл, который я сделал для тестирования:

CXX := x86_64-w64-mingw32-g++
CXX_FLAGS := -static-libgcc -static-libstdc++

main.exe: example.dll test_exe.o
    $(CXX) $(CXX_FLAGS) -o main.exe test_exe.o -L. -lexample

example.dll: example.o
    $(CXX) $(CXX_FLAGS) -shared -o example.dll example.o -Wl,--out-implib,libexample.a

%.o: %.cpp
    $(CXX) -c -fPIC $<

Для справки: у меня есть файл example.hpp, в котором объявлены методы, которые я хочу включить в библиотеку, и эти методы определены в example.cpp. test_exe.cpp содержит мою функцию main и вызывает методы, определенные в библиотеке. Запуск make генерирует (я полагаю) объектные файлы example.o и test_exe.o, за которыми следует динамически связанная библиотека с именем example.dll и соответствующая ей библиотека импорта с именем libexample.a, а затем связывает все вместе в исполняемый файл с именем main.exe. Созданный вывод, похоже, делает это, но у меня нет возможности полностью проверить, действительно ли выходные файлы являются тем, что я ожидаю.

Кроме того, я установил CXX_FLAGS для статической связи стандартных библиотек c и c++, потому что, если я этого не сделаю, я получаю сообщение об ошибке The application was unable to start correctly (0xc000007b). Я предполагаю, что это связано с тем, что по умолчанию файлы ожидают версию стандартных библиотек для Linux (которую нельзя найти на компьютере с Windows), и явное связывание переопределяет этот параметр? Google говорит, что эта ошибка может указывать на то, что у меня неправильная версия приложения для моей машины, поэтому в этом есть смысл.

Отраженные команды, когда я запускаю make:

x86_64-w64-mingw32-g++ -c -fPIC example.cpp
x86_64-w64-mingw32-g++ -static-libgcc -static-libstdc++ -shared -o example.dll example.o -Wl,--out-implib,libexample.a
x86_64-w64-mingw32-g++ -c -fPIC test_exe.cpp
x86_64-w64-mingw32-g++ -static-libgcc -static-libstdc++ -o main.exe test_exe.o -L. -lexample

Когда я связываюсь в Linux, все работает в основном так, как ожидалось. Исполняемый файл работает в Windows, пока .dll находится в текущем каталоге, и выдает ошибку при его удалении.

Во-первых, я не ожидал, что исполняемый файл будет работать независимо от того, присутствует ли библиотека импорта libmath.a. Я предполагал, что связываюсь с библиотекой импорта, которая косвенно обертывает динамическую библиотеку, но, похоже, это не так. Кто-нибудь знает, что на самом деле происходит, и почему я не связываюсь с библиотекой импорта?

Мой другой вопрос требует немного больше пояснений. В идеале я хотел бы иметь возможность создать динамическую библиотеку в Linux, отправить ее на компьютер с Windows и связать там с произвольным исполняемым файлом. Я не совсем уверен, возможно ли это, потому что Windows должна указывать __declspec(dllexport), а Linux — нет, но хотелось бы знать, так ли это. Я попытался переместить свои динамические библиотеки и библиотеки импорта (example.dll и libexample.a) вместе с заголовочным файлом моей библиотеки (example.hpp) в каталог с новым файлом (testapp.cpp), указывающим альтернативный метод main.

На компьютере с Windows я запускаю g++ -c testapp.cpp, чтобы создать объектный файл, а затем пытаюсь связать его. Когда я запускаю g++ -o app.exe testapp.o -L. -lexample, чтобы попытаться сгенерировать исполняемый файл, связанный с динамической библиотекой (через библиотеку импорта), я получаю следующую ошибку: undefined reference to 'square(int)'. square(int) — это функция, определенная в библиотеке, возвращающая квадрат целого числа. Я также попытался пометить функцию в моем заголовочном файле как __declspec(dllimport), что изменило сообщение об ошибке на: undefined reference to '_imp___Z6squarei'. Возможно ли в Windows связать .dll, которая изначально не указывала __declspec(dllexport) для своих функций (т. е. разработанная в Linux)?

Сборка ОС: Ubuntu 20.04 - версия 9.3.0 g++

Целевая ОС: Windows 10 (проверено в виртуальной машине) - версия 9.2.0 g++

Попробуйте связать конкретно с библиотекой импорта, т.е. укажите libexample.a, а не -lexample.

n. m. 18.12.2020 00:21

Та же ошибка. Спасибо за предложение!

Brendan Gould 18.12.2020 01:19

Это странно, ты можешь бегать nm -C libexample.a и nm -CD example.dll?

n. m. 18.12.2020 13:19

Я получаю разные результаты в зависимости от того, в какой ОС я запускаю эти команды. В Windows первая выводит серию строк, например nm: d0000xx.o: file format not recognized, а вторая говорит nm: example.dll: file format not recognized. В linux выводит ряд одинаковых nm: d0000xx.o, но за ними следует то, что, как я предполагаю, является информацией, описывающей каждый идентификатор. Странно, второй мне говорит nm: example.dll: no symbols.

Brendan Gould 18.12.2020 17:29
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
224
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В конце концов я понял. Команда, которая сработала, была: g++ -o alt.exe testapp.o libexample.a. Я не совсем уверен, почему это работает, когда то, что я пробовал раньше, не работало, но теперь оно работает так, как ожидалось.

Что интересно, он все равно работает, даже если я нигде не указываю __declspec(dllimport). Я также не уверен, почему это работает, но я думаю, что я все еще использую компилятор GNU, а не компилятор Windows по умолчанию.

Другие вопросы по теме