前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >libxml2剖析(2):编译

libxml2剖析(2):编译

作者头像
用户7886150
修改2021-02-20 09:52:45
2K0
修改2021-02-20 09:52:45
举报
文章被收录于专栏:bit哲学院

参考链接: C++ wcrtomb()

1、Linux/Unix下的编译

     内容整理自

http://xmlsoft.org/FAQ.html中一些部分。

    跟大多数UNIX库一样,libxml2的编译遵循以下“标准”: 

gunzip -c xxx.tar.gz | tar xvf -  (或者tar xzvf libxml2-xxxx.tar.gz)

cd libxml2-xxxx

./configure --help    查看各选项,然后编译并安装。 

./configure [possible options]

make

make install    安装后有可能还要重新运行ldconfig或类似工具以更新被安装的共享库列表。

     编译时Libxml2无需任何其他的库,正常的C ANSI API就足够了。然而在配置时如果libxml2检测到以下库将会使用它们:

     libz: 一个高可移植的、使用广泛的压缩库。

     iconv: 一个强大的字符编码转换库。缺省情况下它已经被包含到当前的glibc库中,因此在Linux上并不需要另外再安装。关于libiconv库,参见http://www.gnu.org/software/libiconv/。

     安装好之后,应用程序在进行编译和链接时需要知道libxml2的头文件和库文件位置。在上面运行./configure之后会生成一个小的Shell脚本xml2-config,它会被安装成为libxml2的一部分。用这个脚本可以获得需要的编译和链接标志。

     xml2-config --cflags: 打印预处理和编译标志,通常是"-I/usr/local/include/libxml2"。

     xml2-config --libs: 打印库链接信息,通常是"-L/usr/local/lib -lxml2 -lm -ldl"。

     在Makefile中通常是直接如下设置:

 CFLAGS=`xml2-config --cflags`

 LIBS=`xml2-config --libs`

     若要安装到自己指定的目录下,则在配置时使用"--prefix"开关,例如./configure --prefix /home/user/myxml/xmlinst {other configuration options},然后运行make和make install,libxml2库文件、头文件和二进制文件会安装到/home/user/myxml/xmlinst目录下,包括/home/user/myxml/xmlinst/lib,/home/user/myxml/xmlinst/include和/home/user/myxml/xmlinst/bin。为了使用这个“私有”库,你应该先把路径添加到PATH中,export PATH=/home/user/myxml/xmlinst/bin:$PATH。

     现在假设你有一个test.c程序,编译命令为:gcc `xml2-config --cflags --libs` -o test test.c。注意因为/home/user/myxml/xmlinst/bin被添加到了PATH,因此可以找得到xml2-config程序并运行它。

2、Windows下的编译     (1)编译libxml2

     若要在Windows下自行编译libxml2,libxml2-2.9.0\win32\Readme.txt中说明怎样通过命令行来编译,win32\VC10\下有Visual Studio 2010工程文件,可通过VS 2010来编译。下面介绍使用命令行的方式编译。

     第一步:配置源代码

     打开Visual Studio命令提示符,切换到libxml2-2.9.0\win32\下,运行cscript configure.js help,我们可以获得详细的配置选项帮助,包括XML处理器和Win32构建两大类选项。我们做以下配置:

     cscript configure.js iso8859x=yes iconv=no compiler=msvc cruntime=/MT debug=no prefix=c:\libxml2

     这个配置的意思是激活libxml2库的ISO8859X支持、不依赖于iconv库;使用MSVC编译器(缺省值)、C运行库链接选项为/MT、编译成Release版本(缺省值)、编译出来的库、头文件和相关工具安装到c:\libxml2下。

     链接选项/MT表示静态链接多线程版的C运行时函数库(libcmt.lib),编译器自动定义_MT宏。这样生成的程序不会依赖于动态库msvcrt.dll。另外/MD是动态链接多线程版本的C运行时库(msvcrt.dll,导入库为msvcrt.lib),编译器自动定义_MT和_DLL两个宏。/ML是静态链接单线程版本的C运行时库(libc.lib)。而/MTd, /MDd, /MLd选项使用对应调试版的C运行时库(libcmtd.lib, msvcrtd.dll, libcd.lib),编译器自动再多定义一个_DEBUG宏。它们包含了调试信息,并采用了一些保护机制以帮助发现错误,加强了对错误的检测,因此在运行性能方面比不上Release版本。

     第二步:编译

     nmake /f Makefile.msvc

     第三步:安装

     nmake /f Makefile.msvc install

     大功告成,在c:\libxml2下得到我们需要的libxml2库及相关测试工具。bin\下有动态库libxml2.dll及相关工具,lib\下有导入库libxml2.lib,及静态库版本libxml2_a.lib,include\下有导出的所有头文件。这个libxml2.dll不依赖于iconv和zlib(缺省配置是不使用zlib的),也不依赖于C运行库msvcrt.dll。

     Libxml2中默认的内码是UTF-8,所有使用libxml2处理的xml文件,必须首先显式或者默认的转换为UTF-8编码才能被处理。libxml2通常使用iconv库来进行各种编码的转换。这对于多国语言的xml解析至关重要,例如处理中文文档。

     Libiconv是GNU的字符编码转换库,使用LGPL许可,我们需要把它编译成动态链接库。当然我们也可以用其他的字符编码转换库,比如著名的ICU库(International Component for Unicode)。ICU是一个成熟的、广泛应用的库,是IBM与开源组织合作研究,基于"IBM公共许可证"的用于支持软件国际化的开源项目。ICU实现了对数字、日期、货币等设置的国际化支持,提供了强大的BIDI算法,对阿拉伯语和希伯来语等BiDi语言提供了完善的支持。ICU分为ICU4J和ICU4C,分别对应Java和C/C++平台。这个库是在一种无限制的开放源码许可证下发布的,这使它可以用在各种商业程序、开源程序中。详细可参考官网http://site.icu-project.org/。

     ICU库比较大,binary就有几十MB以上。一般使用libiconv就足够了,这也是libxml2缺省使用编码转换库。在编译libxml2时缺省是会链接到iconv库的,我们上面选择的是不链接。最好把libxml2和libiconv编译成两个独立的库,这样就不会有依赖。

     如果选择链接iconv,可以先编译好libiconv库(参看下面介绍),把libiconv-2.dll、导出库iconv.lib和iconv.h拷贝到libxml2-2.9.0\win32\下(或者在配置时指定搜索路径以找到这些文件),然后做如下配置:

     cscript configure.js iso8859x=yes compiler=msvc cruntime=/MT debug=no prefix=c:\libxml2

     这里表示编译时链接到iconv库。注意libxml2链接时搜索的库名为iconv.lib,要确保导入库的名称为iconv.lib,不是的话要改成这个名。编译好之后libxml2.dll依赖于libiconv-2.dll,因此两者需要一起发布。

(2)编译libiconv

     根据官方http://www.gnu.org/software/libiconv/的描述,libiconv和libcharset库以及它们的头文件使用LGPL授权,而iconv程序使用GPL授权,我们只编译libiconv动态库(如果你的应用有闭源需求的话,不能使用GPL的代码)。

     从ftp://ftp.gnu.org/gnu/libiconv/下载最新的libiconv-1.14.tar.gz,新版libiconv已经不提供用Visual Studio的nmake来编译的脚本了,只能用Cygwin、MinGW之类的环境进行编译,参看README.woe32的描述。我们使用MinGW环境来编译,先安装MinGW(http://www.mingw.org/)到C:\MinGW。在libiconv-1.14中,lib\和libcharset\下是libiconv和libcharset库的源码,需要导出的头文件iconv.h在include\下,为iconv.h.in或iconv.h.build.in。它们使用LGPL许可,而其他目录下的源码是GPL许可,我们也无需使用。

     打开MinGW Shell,切换到libiconv-1.14\下。其编译过程与Linux下的编译类似。./configure(收集系统信息,这需要等待比较长的时间),然后make编译。之后可以在libiconv-1.14\include\下看到生成的头文件iconv.h,在libiconv-1.14\lib\.libs\下看到编译好的libiconv-2.dll,但因为使用GNU GCC编译,没有生成.lib导入库。如果需要隐式链接的话,就需要为该dll产生一个导入库。注意导入库是不能跨编译器使用的,在mingw中导入库是.a格式(libiconv.dll.a),而MSVS中则是.lib格式。

     我们可以用Visual Studio的dumpbin.exe和lib.exe工具制作DLL的导入库文件。先用dumpbin.exe输出DEF文件,然后修改DEF文件使之符合语法,再用lib.exe生成.lib文件。

     首先生成dll库的def文件:dumpbin /EXPORTS libiconv-2.dll > iconv.def。输出的iconv.def内容如下:

Microsoft (R) COFF/PE Dumper Version 10.00.30319.01

Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file libiconv-2.dll

File Type: DLL

  Section contains the following exports for libiconv-2.dll

    00000000 characteristics

    50C075A5 time date stamp Thu Dec 06 18:38:29 2012

        0.00 version

           1 ordinal base

          13 number of functions

          13 number of names

    ordinal hint RVA      name

          1    0 00013000 _libiconv_version

          2    1 00011478 aliases2_lookup

          3    2 00011350 aliases_lookup = _locale_charset

          4    3 000120F0 iconv_canonicalize

          5    4 00011908 libiconv

          6    5 00011958 libiconv_close

          7    6 000114C0 libiconv_open = _libiconv_set_relocation_prefix

          8    7 00011970 libiconv_open_into

          9    8 00012580 libiconv_relocate

         10    9 000124C0 libiconv_set_relocation_prefix

         11    A 00011EB8 libiconvctl

         12    B 00011FC8 libiconvlist

         13    C 00012350 locale_charset

  Summary

        1000 .CRT

        1000 .bss

        1000 .data

        1000 .debug_abbrev

        1000 .debug_aranges

        1000 .debug_frame

       1F000 .debug_info

        6000 .debug_line

       18000 .debug_loc

        1000 .debug_pubnames

        1000 .debug_pubtypes

        4000 .debug_ranges

        1000 .debug_str

        1000 .edata

        4000 .eh_frame

        1000 .idata

       CD000 .rdata

        1000 .reloc

        1000 .rsrc

       12000 .text

        1000 .tls    ionv.def需要修改成符合模块定义文件的语法。我们只要关心DEF文件定义里的两个段:LIBRARY段和EXPORTS段。LIBRARY段指出DLL的内部名,这里为libiconv-2;EXPORTS段指出导出的函数或数据。上面数据的中间部分列出了所有导出函数和数据,真正需要是orinal列(表示编号)和name列。把iconv.def修改成如下内容:

LIBRARY      "libiconv-2"

EXPORTS

_libiconv_version  @1

aliases2_lookup    @2

aliases_lookup = _locale_charset  @3

iconv_canonicalize  @4

libiconv  @5

libiconv_close  @6

libiconv_open = _libiconv_set_relocation_prefix  @7

libiconv_open_into  @8

libiconv_relocate  @9

libiconv_set_relocation_prefix  @10

libiconvctl  @11

libiconvlist  @12

locale_charset  @13    最后生成导入库:lib /machine:ix86 /def:iconv.def,生成iconv.lib和iconv.exp文件。发布时包含libiconv-2.dll, iconv.lib和iconv.h即可,并且注意它是使用LGPL许可的。

(3)编译zlib

     如果你还需要zlib来进行压缩的话(这是可选的),还可以编译出zlib库,这个在我的zlib系列文章中有详细介绍。直接用nmake运行zlib-1.2.7\win32\Makefile.msc即可。如下:

     nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" OBJA="inffas32.obj match686.obj"

     编译出zlib1.dll及导入库zlib.lib,头文件为zconf.h和zlib.h。

     好了。如果你嫌上述编译过程麻烦,也可以直接从http://www.zlatkovic.com/libxml.en.html处获取libxml2的编译好的Windows版本,这个版本只提供了头文件、库文件和dll,不包含源代码、例子程序和文档。若用于解析xml,通常只需要下载libxml2库、iconv库和zlib库就行了。现在提供的版本为libxml2-2.7.8.win32.zip,iconv-1.9.2.win32.zip和zlib-1.2.5.win32.zip。注意iconv-1.9.2.win32.zip中包含有iconv.dll动态库和iconv.exe程序,而iconv.exe是GPL授权的,要特别注意版权的问题。最好的方式还是像上面一样自行编译libiconv库。

     若要使用Libxml2,可在Visual Studio 2010中新建一个解决方案Libxm2Learning,里面有一个空的Libxml2Learning Win32控制台项目,设置成Release模式。把libxml2.dll及导入库libxml2.lib拷贝到解决方案的Release目录下,所有头文件(C:\libxml2\include目录)拷贝到解决方案根目录下。另外把libiconv-2.dll,iconv.lib和iconv.h也拷过来。新建应用程序项目时要设置项目属性。在"C/C++ --->Additional Include Directories"中添加..\include\libxml2,以便能使用libxml2库的头文件。"Code Generation"中的运行时库最好设置成/MT,"Linker--->Additional Dependencies"中添加..\Release\libxml2.lib和..\Release\iconv.lib以便链接时能找到导入库。 

     附:用MSVC编译最新的libiconv     最新的libiconv已经不提供用Visual C/C++和nmake来编译了。如果一定要用Visual C++来编译libiconv,我们需要对源码的编译过程做一些分析,然后对源代码做一些调整。     libiconv-1.14中,lib\和libcharset\下是libiconv和libcharset库的源码,需要导出的头文件iconv.h在include\下,为iconv.h.in或iconv.h.build.in。它们使用LGPL许可,而其他目录下的源码是GPL许可,我们也无需使用。iconv.h.build.in中包含一些@开头的符号变量,这是为了提高可移植性而定义的,它们用来收集一些特定于系统的编译构建信息。在用./configure配置源码时,这些变量会被configure扫描到的相关值替换掉,从而生成iconv.h。在Visual C++下编译时没有配置的过程,因此我们需要了解这些变量的含义。     1)@HAVE_VISIBILITY@: 表示是否有__visibility__属性。这是GCC/G++的__attribute__属性扩展,表示导出符号的可见性,这在创建.so动态库时有用。__attribute__((__visibility__("default")))表示导出的符号可见,而__attribute__ ((visibility("hidden")))可以防止从动态库中导出符号。若用Microsoft Visual C++编译器来编译,显然值为0。     2)@DLL_VARIABLE@: 表示后面声明的变量是否是从外部DLL中导入过来的。如果是,本变量值设成__declspec (dllimport);如果不是,则设成空。显然这里可以设成空的。参考configure.ac中对本变量的处理。     在Windows系统中,__declspec(dllimport)用于声明一个导入函数,是说这个函数是从别的DLL(或EXE)导入,我要用。不使用__declspec(dllimport)导入外部函数也能正确编译代码,但使用__declspec(dllimport)使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于DLL中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨DLL边界的函数调用中。但是,必须使用__declspec(dllimport)才能导入DLL中使用的变量。     __declspec(dllexport)用于声明一个导出函数,是说这个函数要从本DLL导出,要给别人用,一般用在开发DLL时。使用这个声明可以省掉在DEF文件中手工定义导出哪些函数的工作。当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出类。     3)@EILSEQ@: EILSEQ是errno.h中定义的一个错误码,表示非法字节序列(例如在MBCS字符串)。 一些系统像SunOS 4没有EILSEQ,一些系统像BSD/OS在其他头文件中有EILSEQ,在这些系统上就需要定义我们自己的EILSEQ。Linux, Windows上有这个错误码,因此无需自己再定义,本变量值为空。     4)@ICONV_CONST@: 表示在"char"前面是否加上"const",例如在Linux系统上./configure后可以看到这个变量替换为空,即使用"char**",而不是"const char**"。Windows上值为"const"。     5)@USE_MBSTATE_T@: 是否使用宽字符处理函数wchar.h。若要支持多种字符集,本变量值为1。mbstate_t类型用于C的字符编码转换函数和C++的字符编码转换类,C/C++标准没有规定具体的数据类型。mbstate_t类型的对象表示转换函数mbrlen, mbrtowc, mbsrtowcs, wcrtomb或wcsrtombs的一个转换状态(这些函数在wchar.h中)。可用mbsinit()函数测试是否处于读入新字符状态。举个例子,有些字符集包含了一类带有状态编码的字符,如很多Latin语言系带有的重音符号(accent),通常用一个编码表示一种accent,其后面的一个字符表示需要添加accent的字符(因此如果需要输出accent本身,后面还得加另外一个字符,比如空格)。这种字符就是表示进入到某种状态,用mbstate_t类型来描述这种状态。     6)@BROKEN_WCHAR_H@: wchar.h是否有bug。在带桌面C工具包的HP Tru64 UNIX系统上有一个bug,包含<wchar.h>之前必须先包含<stdio.h>。在BSD/OS 4.0.1上有一个bug,必须在包含<wchar.h>之前必须先包含stddef.h>,<stdio.h>和<time.h>。本变量标记这样的特殊情况。Linux, Windows上本变量值为0。     7)@HAVE_WCHAR_T@: 是否使用宽字符处理。若上面使用了宽字符处理,本变量值为1。     详细的构建过程可参考一篇文章:http://www.codeproject.com/Articles/302012/How-to-Build-libiconv-with-Microsoft-Visual-Studio     在Libxm2Learning解决方案下添加一个Win32 DLL空项目libiconv,设置编译成Release版本。     第一步:拷贝源文件     把libiconv-1.14\lib\下的"relocatable.h", "relocatable.c"和"iconv.c"拷贝到libiconv项目目录中。     把libiconv-1.14\libcharset\lib\localcharset.c拷贝到libiconv项目目录中。     把libiconv-1.14\libcharset\include\localcharset.h.build.in拷贝到项目中,并重命名为localcharset.h。     把libiconv-1.14\windows\libiconv.rc拷贝到项目目录。     在libiconv项目下创建子目录include,用来放各个头文件。     把libiconv-1.14\include\iconv.h.build.in拷贝到项目include子目录下,并重命名为iconv.h。     把libiconv-1.14\config.h.in拷贝到项目include子目录下,并重命名为config.h。     把libiconv-1.14\lib\下的所有头文件(*.h)和模块定义文件(*.def)拷贝到项目include子目录下。     第二步:设置项目属性     把项目根目录下的两个源文件、两个文件和一个资源文件导入到libiconv项目视图中。设置项目属性。     "VC++ Directories"设置:在"Include Directories"中添加include子目录。     "Preprocessor Definitions"设置:添加宏"BUILDING_LIBICONV"和"BUILDING_LIBCHARSET"。     "Code Generation"设置:"Runtime Library"最好设置为/MT,以静态链接多线程版的C运行时函数库。     第四步:调整源代码     1)iconv.h: 按照上面介绍把各个@...@变量替换成相应值。更改函数导入导出声明,即把以下针对gcc/g++的导出定义  

#if @HAVE_VISIBILITY@ && BUILDING_LIBICONV

#define LIBICONV_DLL_EXPORTED __attribute__((__visibility__("default")))

#else

#define LIBICONV_DLL_EXPORTED

#endif    修改为针对MSVC的定义:

#if BUILDING_LIBICONV

#define LIBICONV_DLL_EXPORTED __declspec(dllexport)

#elif USING_STATIC_LIBICONV

#define LIBICONV_DLL_EXPORTED

#else

#define LIBICONV_DLL_EXPORTED __declspec(dllimport)

#endif    2)libiconv.rc: 在前面添加以下定义。

#define PACKAGE_VERSION_MAJOR       1

#define PACKAGE_VERSION_MINOR       14

#define PACKAGE_VERSION_SUBMINOR    0

#define PACKAGE_VERSION_STRING      "1.14"    3)localcharset.c: 删掉或注释掉以下几行(76-79行)。

/* Get LIBDIR.  */

/*

#ifndef LIBDIR

# include "configmake.h"

#endif

*/    4)iconv.c: 把其中的ICONV_CONST宏(247行)改成const。

     5)localcharset.h: 更改其中函数导出导入的声明。把以下针对gcc/g++的导出定义

#if @HAVE_VISIBILITY@ && BUILDING_LIBCHARSET

#define LIBCHARSET_DLL_EXPORTED __attribute__((__visibility__("default")))

#else

#define LIBCHARSET_DLL_EXPORTED

#endif    修改为针对MSVC的定义:

#ifdef BUILDING_LIBCHARSET

#define LIBCHARSET_DLL_EXPORTED __declspec(dllexport)

#elif USING_STATIC_LIBICONV

#define LIBCHARSET_DLL_EXPORTED

#else

#define LIBCHARSET_DLL_EXPORTED __declspec(dllimport)

#endif    6)config.h: 删掉或注释掉以下内容(29-30行),否则会导致Windows上没有EILSEQ定义,从而代码编译通不过。

/* Define as good substitute value for EILSEQ. */

/*#undef EILSEQ*/    好了,一切准备就绪,编译完之后就可以在解决方案的Release目录中看到libiconv.dll了,以及导入库libiconv.lib(若让libxml2链接时使用,则需要改名为iconv.lib)。发布时还包含头文件iconv.h。

     打开Visual Studio的命令提示符,运行dumpbin /EXPORTS libiconv.dll,可以看到DLL导出的各个函数名。

Microsoft (R) COFF/PE Dumper Version 10.00.30319.01

Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file libiconv.dll

File Type: DLL

  Section contains the following exports for libiconv.dll

    00000000 characteristics

    50B5EAAA time date stamp Wed Nov 28 18:42:50 2012

        0.00 version

           1 ordinal base

           9 number of functions

           9 number of names

    ordinal hint RVA      name

          1    0 000E8DC0 _libiconv_version = __libiconv_version

          2    1 00012810 iconv_canonicalize = _iconv_canonicalize

          3    2 000120C0 libiconv = _libiconv

          4    3 00012100 libiconv_close = _libiconv_close

          5    4 00011D90 libiconv_open = _libiconv_open

          6    5 00012120 libiconv_open_into = _libiconv_open_into

          7    6 00012420 libiconvctl = _libiconvctl

          8    7 00012600 libiconvlist = _libiconvlist

          9    8 00012970 locale_charset = _locale_charset

  Summary

        3000 .data

       CE000 .rdata

        2000 .reloc

        1000 .rsrc

       19000 .text        原始的libiconv使用LGPL许可,因此这个调整的libiconv也是LGPL许可,在使用时必须仔细注意授权的问题。如果动态链接libiconv.dll,则你的应用程序无需发布源码。如果编译成静态库并使用静态链接,则你的应用程序或者发布源码,或者发布目标文件(*.obj),以便其他人通过静态链接LGPL的libiconv来重新生成应用程序。

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
区块链
云链聚未来,协同无边界。腾讯云区块链作为中国领先的区块链服务平台和技术提供商,致力于构建技术、数据、价值、产业互联互通的区块链基础设施,引领区块链底层技术及行业应用创新,助力传统产业转型升级,推动实体经济与数字经济深度融合。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档