Я работаю над переносным приложением, которое работает под Linux и Windows.
Я кросс-компиляции в системе Linux, используя cmake, gcc 4.4.4 и mingw-gcc 4.4.4.
Я могу без проблем скомпилировать и связать версию своего приложения для Linux. Однако, если я пытаюсь кросс-компилировать для Windows, приложение компилируется нормально, но компоновщик заканчивается ошибкой «неопределенная ссылка».
Вот выдержка из исходного кода:
Заголовочный файл (fileactions.hpp):
class FileActions {
bool CopyFile(const std::string &source, const std::string &destination);
bool CopyFile(const boost::filesystem::path& source, const boost::filesystem::path& destination);
};
Исходный файл (fileactions.cpp):
bool FileActions::CopyFile(const boost::filesystem::path& source, const boost::filesystem::path& destination)
{
return this->CopyFile(source.string(), destination.string());
}
bool FileActions::CopyFile(const std::string &source, const std::string &destination)
{
/* ... do something */
}
Выдержка из кода, который вызывает ошибку ссылки:
bool TmmProject::PostImportOldVersion(int old_version) {
namespace fs = boost::filesystem;
FileActions dd;
fs::path backup;
/* fs::path _location; // This is actually defined in the class declaration */
/* do something more */
if( !dd.CopyFile(_location, backup ) ) { <-- I get the linker error at this line
log << "<span style=\"color:red\">Failed to create backup file. Stopping import </span><br>";
log << "The error message is: " << dd.GetError() << "<br>";
_last_error = log.str();
return false;
}
/* do something more */
}
Как уже говорилось, приведенный выше код прекрасно работает, если я компилирую для системы linux, но не работает, если я использую mingw для компиляции для Win32. Точная ошибка компоновщика:
CMakeFiles/tmm.dir/tmmproject.cpp.obj:/.../tmm/tmmproject.cpp:408: undefined reference
to 'tmm::fileActions::CopyFileA(
boost::filesystem::basic_path<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::filesystem::path_traits> const &,
boost::filesystem::basic_path<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::filesystem::path_traits> const &
)'
Файл fileactions.cpp связан со статическим libray libtmm. Класс TmmProject, который вызывает ошибку, является частью той же библиотеки.
CMakeLists.txt, который используется для ссылки на библиотеку, выглядит следующим образом (сокращенно):
include_directories( ... )
link_directories ( ${Boost_LIBRARY_DIRS} )
file(GLOB TMM_HEADERS *.h)
file(GLOB TMM_SOURCES *.cpp)
set ( TMM_LIBS
${Boost_LIBRARIES}
${PYTHON_LIBRARIES}
m
)
IF( WIN32 )
ADD_LIBRARY( tmm STATIC ${TMM_SOURCES} )
target_link_libraries( tmm ${TMM_LIBS} )
# I found the following option from a similar quesiton in this froum, but
# actually it does not seem to make any difference
SET_TARGET_PROPERTIES( tmm PROPERTIES LINK_FLAGS -Wl,--export-all-symbols )
ELSE( WIN32 )
ADD_LIBRARY( tmm SHARED ${TMM_SOURCES} )
target_link_libraries( tmm ${TMM_LIBS} )
INSTALL(TARGETS tmm DESTINATION lib)
ENDIF( WIN32 )
Есть ли у кого-нибудь идея, в чем может быть причина неудачи?
Microsoft использует много определений в своем заголовке для поддержки юникода. В вашем случае имя OpenFile
Кажется, также определено быть Eiter OpenFileA
или если вы переключитесь на Unicode, это будет OpenFileW
,
Чтобы избавиться от этой проблемы, добавьте это после включения заголовков от Microsoft.
#undef CopyFile
Вы можете, конечно, упаковать его в #ifdef
ограничить это платформой Microsoft.
Microsoft использует макросы для того, чтобы приложения могли использовать формы UNICODE (широкий или 16-разрядный символ) и ASCII (8-разрядный символ) для системных вызовов. Так что где-то в Windows.h есть что-то вроде:
#if UNICODE
#define CopyFile CopyFileW
#else
#define CopyFile CopyFileA
#endif
Во время использования #undef CopyFile
(и аналогичные) будет работать, я бы посоветовал вам избегать <windows.h>
если это НЕОБХОДИМО АБСОЛЮТНО — если нужно, попробуйте ограничить его небольшим числом (в идеале одним) исходным файлом, который фактически напрямую взаимодействует с Widnows.