c++ - 如何将我的应用静态链接到 ICU 57.1 MinGW

标签 c++ static qt-creator mingw32 icu

我使用 MinGW x32 静态构建了 ICU 57.1; 结果,我在lib目录下得到了如下文件:

libsicudt.a
libsicuin.a
libsicuio.a
libsicule.a
libsiculx.a
libsicutest.a
libsicutu.a
libsicuuc.a
sicudt.a
sicudt.dll

现在我想运行其中一个示例,但无论我尝试什么 我收到类似的错误 “对 unum_ 的 undefined reference ... unum_setAttribute unum_formatInt64 u_isspace”。 开始时的错误总数约为 1700。 分析 pkgconfig 文件我发现了一些相互依赖和 在 cmd 行中重新排序 .a 文件后,错误减少到 82 个。

但我不知道下一步该去哪里。 谷歌显示很多人在 ICU 上有同样的问题,但 到目前为止,还没有对我有用并能解释原因的解决方案。

构建时,为了方便,我使用Qt Creator,这是我的.pro文件:

TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt

SOURCES += main.cpp

ICUDIR=$$(ICU_PATH)
ICU_LIBPATH=$$ICUDIR"/dist/lib/"
INCLUDEPATH += $$ICUDIR"/dist/include"

LIBS += $$ICU_LIBPATH"libsicuuc.a" $$ICU_LIBPATH"libsicudt.a"  \
$$ICU_LIBPATH"libsicuin.a" $$ICU_LIBPATH"libsicuio.a"  \
$$ICU_LIBPATH"libsicule.a" $$ICU_LIBPATH"libsiculx.a"  \
$$ICU_LIBPATH"libsicutu.a" $$ICU_LIBPATH"sicudt.a"

我有以下问题: 1) 任何人都可以编写一个简单的单行静态构建命令吗 使用 g++ 的最简单的 ICU 应用程序?有可能吗? 2) 将 .a 文件传递​​给链接器时,它们的正确顺序是什么? 3) 什么是文件 libsicudt.a、sicudt.a 和 sicudt.dll? 4) 我上面写的文件列表是完整的还是我的构建损坏了? 5) 有什么我遗漏的错误吗?

最佳答案

终于,我解决了这个问题。为了与您分享我的经验 我将描述我遇到的四个主要陷阱。 如果您想重复这些步骤,我假设您使用的是 msys2 和 MinGW-w32。

  1. 对所有内容使用相同的工具链。请注意,MinGW、MinGW-w32 和 MinGW-w64 是 3 个不同的工具链。如果您有多个 MinGW 安装 像我一样,确保在整个项目中只使用其中一个。 出于兼容性原因,我选择了 MinGW-w32。

  2. 最新版本的软件通常包含错误,并且它们 需要你再用手鼓跳舞。 在撰写本文时,ICU v58 存在问题。 解决方案是恢复到旧版本(在我的例子中是 57.1)。

  3. 在构建 ICU 库之前,请确保正确设置所有内容。 这里的问题是使用 namespace 和重命名 namespace ICU 默认执行。

找到文件C:\icu\source\common\unicode\uconfig.h,添加以下内容 在包括守卫之后的开头:

#define U_DISABLE_RENAMING  1
#define U_USING_ICU_NAMESPACE 0

保存文件。打开 MSYS2 终端并将 mingw-w32 设置为工作工具集:

export PATH="/c/msys64/mingw32/bin:$PATH"

转到 icu/source 目录:

cd /c/icu/source

为不重命名且 U_USING_ICU_NAMESPACE=0 的静态构建配置 ICU:

export CFLAGS="-DU_CHARSET_IS_UTF8=1 -DU_GNUC_UTF16_STRING=1 -DU_STATIC_IMPLEMENTATION"
export CXXFLAGS="-DU_USING_ICU_NAMESPACE=0 -std=gnu++11 -DU_CHARSET_IS_UTF8=1 -DU_GNUC_UTF16_STRING=1 -DU_HAVE_CHAR16_T=1 -DUCHAR_TYPE=char16_t -Wall --std=c++11 -DU_STATIC_IMPLEMENTATION" -static-libstdc++ -fno-exceptions 
export CPPFLAGS="-DU_DISABLE_RENAMING=1 -DU_CHARSET_IS_UTF8=1 -DU_STATIC_IMPLEMENTATION"
export LDFLAGS="-std=gnu++11"

./runConfigureICU MinGW prefix=$PWD/../dist -enable-static -disable-shared --disable-renaming

构建并安装 ICU 库。如果你有 4 个核心,-j4 会加速这个过程:

mingw32-make -j4
mingw32-make install

清理中间文件:

mingw32-make clean

现在你应该有位于 icu/dist/lib 的静态库。

陷阱 4:静态链接时,您应该将库传递给 链接器顺序正确。这只对静态链接很重要。 但是如何确定哪个顺序是正确的呢? 这里 pkg-config 工具派上用场了。 它的作用如下:将库包名称作为 参数,计算依赖关系并返回完整的字符串 可以直接提供给编译器的参数 或由您查看以了解幕后发生的事情。

有 5 个包位于 C:\icu\dist\lib\pkgconfig。 让我们为 pkg-config 配置路径:

export PKG_CONFIG_PATH="/c/icu/dist/lib/pkgconfig:$PKG_CONFIG_PATH"

为了测试它,输入:

pkg-config --static --cflags --libs icu-uc icu-i18n icu-io icu-le icu-lx

输出应该是:

-IC:/icu/dist/include -LC:/icu/dist/lib -lsicuio -lsicuin -lsiculx -lsicule -lsicuuc -lsicudt -lpthread -lm

这是我们必须传递给编译器的字符串。

作为最终测试,我们将使用命令行编译一个简单的示例应用程序:

创建文件夹/c/icu/dist/test,里面有文件test.cpp:

#include <unicode/unistr.h>
#include <unicode/ustdio.h>
#include <unicode/brkiter.h>
#include <stdlib.h>

using namespace icu;

void printUnicodeString(UFILE *out, const UnicodeString &s) {
    UnicodeString other = s;
    u_fprintf(out, "\"%S\"", other.getTerminatedBuffer());
}

int main( void )
{
    UFILE *out;
    UErrorCode status  = U_ZERO_ERROR;
    out = u_finit(stdout, NULL, NULL);
    if(!out) {
        fprintf(stderr, "Could not initialize (finit()) over stdout! \n");
        return 1;
    }
    ucnv_setFromUCallBack(u_fgetConverter(out), UCNV_FROM_U_CALLBACK_ESCAPE,
        NULL, NULL, NULL, &status);
    if(U_FAILURE(status)) {
        u_fprintf(out, "Warning- couldn't set the substitute callback - err %s\n", u_errorName(status));
    }

    /* End Demo boilerplate */

    u_fprintf(out,"ICU Case Mapping Sample Program\n\n");
    u_fprintf(out, "C++ Case Mapping\n\n");

    UnicodeString string("This is a test");

    u_fprintf(out, "\nstring: ");
    printUnicodeString(out, string);
    string.toUpper(); /* string = "THIS IS A TEST" */
    u_fprintf(out, "\ntoUpper(): ");
    printUnicodeString(out, string);

    return 0;
}

进入测试目录:

cd /c/icu/dist/test

g++ -o test test.cpp  \
 `pkg-config --cflags --libs --static icu-uc icu-i18n icu-io icu-le icu-lx`

运行应用:

./test

也许这不是最好的方法, 特别是关于工作空间,但它有效。

更多关于 pgk-config 的信息: https://people.freedesktop.org/~dbn/pkg-config-guide.html

关于c++ - 如何将我的应用静态链接到 ICU 57.1 MinGW,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41143845/

相关文章:

java - 在java中的子类(子类)中初始化静态最终变量

c++ - lua/C++ 对象与静态成员的绑定(bind)

c++ - Qt creator 无法解析 stddef.h --> 不正确的代码完成和突出显示

qt-creator - 调试时QtCreator的标准输出在哪里?

Code::Blocks 中的 C++ 非类成员编译错误?

文件的 C++ 输出流不起作用

c++ - 使用另一个点和它们之间的角度计算圆上的点

c++ - 是否可以在 Qt 中同时使用静态库和动态库

swift - 具有静态方法的服务对象的结构、类或枚举?

Qt 创作者 : is there something like VS solution in which you can add projects and set project dependencies and build order?