1

我正在开发一个在 Linux 和 Windows 下运行的便携式应用程序。我正在使用 cmake、gcc 4.4.4 和 mingw-gcc 4.4.4 在 linux 系统上进行交叉编译。

我可以毫无问题地编译和链接我的应用程序的 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 链接到静态库 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 )

有没有人知道失败的原因是什么?

4

2 回答 2

1

这是 Microsoft 使用宏允许应用程序使用“UNICODE”(宽字符或 16 位字符)和“ASCII”(8 位字符)形式的 ssystem 调用。所以在 Windows.h 的某个地方有类似的东西:

#if UNICODE
#define CopyFile CopyFileW
#else
#define CopyFile CopyFileA
#endif

虽然使用#undef CopyFile(和类似的)会起作用,但我建议您避免包含<windows.h>,除非绝对必要 - 如果必须,请尝试将其限制为实际上直接与 Widnows 交互的少量(理想情况下是一个)源文件。

于 2013-06-10T09:27:02.460 回答
1

Microsoft 在其标头中使用了大量定义来支持 unicode。在您的情况下,名称OpenFile似乎也被定义为 eiterOpenFileA或者如果您切换到 unicode ,它将是OpenFileW.
为了摆脱这个问题,在包含来自微软的标题之后添加这个。

#undef CopyFile

您当然可以将其打包成一个#ifdef以将其限制在 microsoft 平台上。

于 2013-06-10T09:23:24.287 回答