1

I am working on a portable application which is running under Linux and Windows. I am cross compiling on a linux system using cmake, gcc 4.4.4 and mingw-gcc 4.4.4.

I can compile and link the Linux version of my application without problems. However if I try to cross-compile for Windows, the application compiles fine, but the linker ends with an 'undefined reference' error.

Here is the excerpt from the source code:

Header File (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);
};

Source file (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 */
}

Excerpt from code which causes the link-error:

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 */
} 

As said, above code links fine if I compile for linux system, but fails if I use mingw to compile for Win32. The exact linker error is:

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 &
)'

The file fileactions.cpp is linked into a static libray libtmm. The TmmProject class, which causes the error, is part of the the same library.

The CMakeLists.txt which is used to link the library looks like this (shortened):

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 )

Has anyone an Idea what could be the reason for the failure?

2 Answers 2

1

Microsoft is using a lot of defines in their header for unicode support. In your case the name OpenFile seems also to be defined to be eiter OpenFileA or if you switch to unicode it would be OpenFileW.
To get rid of this problem add this after including the headers from microsoft.

#undef CopyFile

You can of course pack it into a #ifdef to limit it to the microsoft platform.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your quick answer. As I wrote in the comment to the other answer, this was the cause for the problem. Using #undef did not work for me, but renaming my library functions solved the issue.
1

This is Microsoft using macros to allow applications to use "UNICODE" (wide or 16-bit character) and "ASCII" (8-bit character) forms of the ssystem calls. So somewhere in Windows.h there is something like:

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

Whilst using #undef CopyFile (and similar) will work, I would suggest that you avoid including <windows.h> unless ABSOLUTELY necessary - if you have to, try to limit that to a small number (ideally one) source file that actually directly interacts with Widnows.

1 Comment

Thank you very much for your quick answer! This was actually the problem. Unfortunately, "windows.h" was not included by myself, but by some libaray header I was using. So my final solution was to rename the methods FileActions::CopyFile to something else.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.