C++ Linux 到 Windows 交叉编译错误

Posted

技术标签:

【中文标题】C++ Linux 到 Windows 交叉编译错误【英文标题】:C++ Linux to Windows Cross-compilation error 【发布时间】:2016-10-21 19:46:51 【问题描述】:

我正在尝试为 linux 中的 windows 编译一个 C++ 程序。该程序使用 SHGetKnownFolderPath 函数。每当我尝试编译它时,都会出现以下错误:

$ x86_64-w64-mingw32-g++ main.cpp main.h -mwindows -o main.exe
/tmp/cc7yIaVK.o:main.cpp:(.text+0x11c): undefined reference to `SHGetKnownFolderPath'
/tmp/cc7yIaVK.o:main.cpp:(.rdata$.refptr.FOLDERID_Startup[.refptr.FOLDERID_Startup]+0x0): undefined reference to `FOLDERID_Startup'
collect2: error: ld returned 1 exit status

这是我写的代码:

int WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd)
    //get startup folder
    if(SHGetKnownFolderPath(FOLDERID_Startup, 0, NULL, &startupFolder) != S_OK)
        //error in getting startup folder
        return -1;
    
  /*
  ...
  */

我包含了正确的头文件并定义了 windows 版本:

#define WINVER 0x0600
#define _WIN32_WINNT 0x0600
#include <shlobj.h>

编辑:根据 mingw.org 文档,我了解到我必须在编译中链接一个 lib 文件,大概是在源文件名之后使用 -l 标志。我不知道我需要的文件的名称是什么。

我不知道还能做什么。

【问题讨论】:

#includes 和 #defines 仅对编译时间感兴趣。您没有编译错误,但有链接器错误。所以你需要弄清楚你必须与你的东西链接什么,以便为链接器提供它需要的东西。 github.com/HandBrake/HandBrake/issues/112 有帮助吗? @Alfe 我也在 google 上看到了该链接,但它不起作用。显然,这些网站现在受到 DDoS 攻击:pcworld.com/article/3133847/internet/… SHChangeNotifyRegister with QT/MinGW 4.8 cannot link的可能重复 @krOoze 该帖子谈到了 Qt(我没有使用)和 Windows(我没有使用)(从答案中的 DOS 样式路径猜测)。该帖子提供的解决方案不适用于此处。 @Yapoz 很好。不过,该功能似乎在 shell32 中,需要以某种方式链接。 【参考方案1】:

快速查找/nm(具有识别 Windows 二进制文件的合适 nm)0 给出:

rich@dev:~/ellcc-release/libecc/mingw/x86_64-w64-mingw32$ find . -name "*.a" | xargs ~/ellcc/bin/ecc-nm -A | grep FOLDERID_Startup
/home/rich/ellcc/bin/ecc-nm: ./sys-root/mingw/lib/libruntimeobject.a: File format not recognized
./sys-root/mingw/lib/libuuid.a:lib64_libuuid_a-uuid.o:0000000000000000 r .rdata$FOLDERID_Startup
./sys-root/mingw/lib/libuuid.a:lib64_libuuid_a-uuid.o:0000000000000000 R FOLDERID_Startup
rich@dev:~/ellcc-release/libecc/mingw/x86_64-w64-mingw32$

看起来 -luuid 是您所需要的。

我做了一个小测试程序:

rich@dev:~$ cat win.c 
#define WINVER 0x0600
#define _WIN32_WINNT 0x0600
#include <shlobj.h>
int WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd)
    const char *startupFolder;
    //get startup folder
    if(SHGetKnownFolderPath(&FOLDERID_Startup, 0, NULL, &startupFolder) != S_OK)
        //error in getting startup folder
        return -1;
    
  /*
  ...
  */


rich@dev:~$ ~/ellcc/bin/ecc -target x86_64-w64-mingw32 win.c -luuid
win.c:7:57: warning: incompatible pointer types passing 'const char **' to
      parameter of type 'PWSTR *' (aka 'unsigned short **')
      [-Wincompatible-pointer-types]
    if(SHGetKnownFolderPath(&FOLDERID_Startup, 0, NULL, &startupFolder) != S...
                                                        ^~~~~~~~~~~~~~
/home/rich/ellcc/bin/../libecc/mingw/include/shlobj.h:746:92: note: passing
      argument to parameter 'ppszPath' here
  ...(REFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath);
                                                                  ^
1 warning generated.
rich@dev:~$

【讨论】:

您好,感谢您的回答。 -luuid 似乎修复了 FOLDERID_Startup 问题,但在我的错误中我仍然得到对SHGetKnownFolderPath 的未定义引用。我原以为这将通过相同的解决方案来解决。它在这里抱怨它:/tmp/cc5KqFce.o:main.cpp:(.text+0x150) 而不是在 main.cpp 上写一行,所以我认为这是另一个链接器错误。 该符号在 libshel​​l32.a 中定义。我的 clang/mingw 默认包含它,抱歉。添加 -lshell32 应该可以解决它。 不,同样的错误。 -lshell32 似乎没有做任何事情,而 -luuid 删除了 2 个错误中的 1 个,如果这有帮助的话。 这很奇怪,如果我从默认库列表中删除它,链接会失败,但这条线有效:~/ellcc/bin/ecc -target x86_64-w64-mingw32 win.c -luuid - lshell32 也许这与我使用 C++ 而不是 C 的事实有关?如果重要的话,这是我的线路(不起作用):x86_64-w64-mingw32-g++ main.cpp main.h -luuid -lshell32 -o main.exe

以上是关于C++ Linux 到 Windows 交叉编译错误的主要内容,如果未能解决你的问题,请参考以下文章

windows eclipse c++怎么交叉编译linux

从linux交叉编译到windows一个visual studio项目

在 Windows 7 中交叉编译 C 和 C++ 应用程序,在 linux 下使用 MinGW

在 linux 上用 Eclipse 交叉编译,在 windows 上用 eclipse 交叉编译?

在 Windows 上运行并生成 Linux 代码的 C++ 编译器

从 Mac 为 Windows、Linux 交叉编译 C++/QT [关闭]