How to build libiconv with VC2017
最近解決了VC2017編譯libiconv的問題,總結一下經驗和收獲。
按照GNU libiconv官方的README.windows文檔“2) Native binaries, built using the MS Visual C/C++ tool chain.”的說明,應該是在Cygwin環境下使用Visual C/C++ 9.0或以上版本進行。
網上介紹VC編譯libiconv的文章很多,采用官方推薦做法的卻很少,奇哉怪也!我在解決的過程中發現原來這個過程有好幾個坑,可能是因為這個原因吧。
1. fprintf()輸出’\n’換行符問題
libiconv/lib/genaliases.c輸出’\n’到以文本方式打開的canonical.sh,這導致在Cygwin中生成的Unix腳本文件用的換行符卻是DOS格式,然后導致腳本中的sed程序處理出錯。
這個問題已在官方代碼庫修正(在libiconv-1.15之后),改為以二進制方式打開文件。
參考
[1] Avoid end-of-lines problem in generated shell scripts on Cygwin.
[2] Text and Binary modes
2. windres的-F參數問題
在libiconv/lib/Makefile.in中:
libiconv.res.lo : $(srcdir)/../windows/libiconv.rc$(LIBTOOL_COMPILE) --tag=RC $(RC) `$(SHELL) $(srcdir)/../windows/windres-options --escape $(PACKAGE_VERSION)` -i $(srcdir)/../windows/libiconv.rc -o libiconv.res.lo --output-format=coff在libiconv/src/Makefile.in中:
iconv.res : $(srcdir)/../windows/iconv.rc$(WINDRES) `$(SHELL) $(srcdir)/../windows/windres-options --escape $(PACKAGE_VERSION)` -i $(srcdir)/../windows/iconv.rc -o iconv.res --output-format=coff這里$(RC)和$(WINDRES)在生成的Makefile中就對應了Cygwin的windres程序。(不能用Windows平臺的rc.exe,因為它不支持output-format參數)。
libiconv的出現遠早于64位Windows。在64位Windows的Cygwin64終端上,windres默認將rc資源文件編譯成64位的res文件。如果要編譯的是32位的libiconv,link鏈接時就出錯了。
解決辦法是在”configure”的運行參數中增加
如果是64位的目標,則增加:
RC="windres -Fpe-x86-64" WINDRES="windres -Fpe-x86-64"鏈接器link也有類似問題,需要在LDFLAGS中添加“/MACHINE:X86”或“/MACHINE:X64”。
這個問題只能建議官方更新README.windows文檔了。
參考
[1] windres
3. UTF-8字符導致C4819編譯警告的問題
先看這個補丁:Use Unicode single-quotes in comments.
對于Windows系統區域和語言設置不是英語的用戶,代碼中的UTF-8字符會導致MSVC報告C4819編譯警告。
關鍵問題是編譯器不能正確處理后續代碼了,后面經常就跟著報編譯錯誤,然后是編譯失敗和鏈接失敗。
關于這個問題網上也有很多解決方案:
a. 修改Windows區域和語言設置
改成英語國家,就是日常使用不太方便了。可能美國同行都沒注意到有UTF-8導致C4819這回事。
b. 轉碼后保存
網上很多介紹怎么通過VC界面手動保存的,不抄了。我自己寫的bash版:
if [ ! `regtool -q check/HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Nls/CodePage/OEMCP` ]; thenTOCODEPAGE=`regtoolget /HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Nls/CodePage/OEMCP`cp include/iconv.h include/iconv.h.backupiconv-c -f utf-8 -t cp"${TOCODEPAGE}" include/iconv.h 1>include/iconv.h.tmpmv include/iconv.h.tmp include/iconv.hmakemake checkmake installmv include/iconv.h.backup include/iconv.hfi之前為另一項目做的DOS批處理文件版:
FOR %%X IN (src\*.*, include\artilist.h, dat\*.*, win\win32\*.c) DO (iconv.exe -c -f utf-8 -t gb18030 %%X 1> %%X.gbmv.exe %%X.gb %%X )c. 不修改代碼
給CFLAGS和CXXFLAGS加”/utf-8”參數,詳見下面的參考[1]。
d. 不要在C/C++代碼里用UTF-8
把前面提到的補丁取消掉是最好的,畢竟iconv.h還要導出給庫用戶使用的,不改的話就是把問題推給用戶了。
C/C++源文件最好只用ASCII字符編碼。有多語言需求的可以放到程序外去實現,比如配置文件、數據庫或其他明確支持UTF-8的腳本語言。
參考
[1] /utf-8 (Set Source and Executable character sets to UTF-8)
[2] Unicode Support in the Compiler and Linker
[3] Compile error with source file containing UTF8 strings (in CJK system locale)
[4] It is impossible to use UTF-8 without BOM in source files.
4. build-vc2017.sh
我寫的輔助腳本,僅供參考。
#!/bin/sh if [ ! -f configure ]; thenecho Install Cygwin packages: autoconf make automake gcc-core gettext-devel git gperf groff m4 patchecho Then run ./autogen.sh before this script.exit 1 fi# Set PlatformTarget # Remember to "make clean" after switching PlatformTarget, before running this script again. #PlatformTarget=x64 if [ -z "${PlatformTarget}" ]; thenPlatformTarget=x86 fi# Get WindowsSdkDir #WindowsSdkDir='C:\\Program Files (x86)\\Windows Kits\\10\\' if [ -z "${WindowsSdkDir}" ]; thenREGISTRY1=/HKEY_LOCAL_MACHINE/SOFTWARE/Wow6432Node/Microsoft/Microsoft\ SDKs/Windows/v10.0REGISTRY2=/HKEY_CURRENT_USER/SOFTWARE/Wow6432Node/Microsoft/Microsoft\ SDKs/Windows/v10.0REGISTRY3=/HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Microsoft\ SDKs/Windows/v10.0REGISTRY4=/HKEY_CURRENT_USER/SOFTWARE/Microsoft/Microsoft\ SDKs/Windows/v10.0if [ ! `regtool -q check "${REGISTRY1}/InstallationFolder"` ]; thenWindowsSdkDir=`regtool get "${REGISTRY1}/InstallationFolder"`elif [ ! `regtool -q check "$REGISTRY2/InstallationFolder"` ]; thenWindowsSdkDir=`regtool get "${REGISTRY2}/InstallationFolder"`elif [ ! `regtool -q check "$REGISTRY3/InstallationFolder"` ]; thenWindowsSdkDir=`regtool get "${REGISTRY3}/InstallationFolder"`elif [ ! `regtool -q check "$REGISTRY4/InstallationFolder"` ]; thenWindowsSdkDir=`regtool get "${REGISTRY4}/InstallationFolder"`elseecho Cannot find WindowsSdkDirexit 1;fi fiif [ ! -d "${WindowsSdkDir}" ]; thenecho Cannot find WindowsSdkDir ${WindowsSdkDir}exit 1 fi# Set WindowsSDKVersion #WindowsSDKVersion='10.0.15063.0' #WindowsSDKVersion='10.0.14393.0' #WindowsSDKVersion='10.0.10586.0' #WindowsSDKVersion='10.0.10240.0' if [ -z "${WindowsSDKVersion}" ]; thenWindowsSDKVersion='10.0.16299.0' fi# Set VSINSTALLDIR VSINSTALLDIR='D:\Program Files (x86)\Microsoft Visual Studio\2017\Community\' #VSINSTALLDIR='E:\Program Files (x86)\Microsoft Visual Studio\2017\Community\' #VSINSTALLDIR='F:\Program Files (x86)\Microsoft Visual Studio\2017\Community\' #VSINSTALLDIR='G:\Program Files (x86)\Microsoft Visual Studio\2017\Community\' if [ -z "${VSINSTALLDIR}" ]; thenVSINSTALLDIR='C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\' fi# Set VSToolsVersion #VSToolsVersion='14.11.25503' if [ -z "${VSToolsVersion}" ]; thenVSToolsVersion='14.11.25503' fiecho PlatformTarget=${PlatformTarget} echo WindowsSdkDir=${WindowsSdkDir} echo WindowsSDKVersion=${WindowsSDKVersion} echo VSINSTALLDIR=${VSINSTALLDIR} echo VSToolsVersion=${VSToolsVersion} echo# Verify WindowsSdkIncludeDir and WindowsSdkLibDir WindowsSdkIncludeDir="${WindowsSdkDir}"'Include\'"${WindowsSDKVersion}" WindowsSdkLibDir="${WindowsSdkDir}"'Lib\'"${WindowsSDKVersion}" if [ ! -d "${WindowsSdkIncludeDir}" ]; thenecho Cannot find WindowsSdkIncludeDir ${WindowsSdkIncludeDir}echo Modify WindowsSDKVersion value and run again.exit 1 fi if [ ! -d "${WindowsSdkLibDir}" ]; thenecho Cannot find WindowsSdkLibDir ${WindowsSdkLibDir}echo Modify WindowsSDKVersion value and run again.exit 1 fi# Windows C library headers and libraries. WindowsCrtIncludeDir="${WindowsSdkIncludeDir}\\ucrt" WindowsCrtLibDir="${WindowsSdkLibDir}"'\ucrt\'"${PlatformTarget}" if [ ! -f "${WindowsCrtIncludeDir}\\stdio.h" ]; then echo Cannot locate ${WindowsCrtIncludeDir}\\stdio.hexit 1 fi if [ ! -f "${WindowsCrtLibDir}\\ucrt.lib" ]; thenecho Cannot locate ${WindowsCrtLibDir}\\ucrt.libexit 1 fi INCLUDE="${WindowsCrtIncludeDir};$INCLUDE" LIB="${WindowsCrtLibDir};$LIB"# Windows API headers and libraries. INCLUDE="${WindowsSdkIncludeDir}\\um;${WindowsSdkIncludeDir}\\shared;$INCLUDE" LIB="${WindowsSdkLibDir}"'\um\'"${PlatformTarget};$LIB"# Visual C++ tools, headers and libraries. VCToolsInstallDir="${VSINSTALLDIR}"'VC\Tools\MSVC\'"${VSToolsVersion}" if [ ! -f "${VCToolsInstallDir}\\include\\stdarg.h" ]; thenecho Cannot locate ${VCToolsInstallDir}\\include\\stdarg.hecho Modify VSINSTALLDIR and VSToolsVersion values and run again.exit 1 fi INCLUDE="${VCToolsInstallDir}\\include;$INCLUDE" LIB="${VCToolsInstallDir}"'\lib\'"${PlatformTarget};$LIB"export INCLUDE LIB #echo INCLUDE=${INCLUDE} #echo LIB=${LIB} #echo #read -n1 -p "Verify the above settings. Press CTRL-C to abort, or other keys to continue..."[ -d $HOME/msvc/ ] || mkdir $HOME/msvc/ cp gnulib/build-aux/ar-lib $HOME/msvc/ && chmod a+x $HOME/msvc/ar-lib cp gnulib/build-aux/compile $HOME/msvc/ && chmod a+x $HOME/msvc/compileif [ "${PlatformTarget}" == "x86" ]; thenexport PATH=`cygpath -u "${VCToolsInstallDir}"`/bin/Hostx86/x86:`cygpath -u "${WindowsSdkDir}"`bin/"${WindowsSDKVersion}"/x86:"$PATH"win32_target=_WIN32_WINNT_WIN7./configure --host=i686-w64-mingw32 --prefix=/usr/local/msvc32 \CC="$HOME/msvc/compile cl -nologo" \CFLAGS="-MD /utf-8" \CXX="$HOME/msvc/compile cl -nologo" \CXXFLAGS="-MD /utf-8" \CPPFLAGS="-D_WIN32_WINNT=$win32_target" \RC="windres -Fpe-i386" \WINDRES="windres -Fpe-i386" \LDFLAGS="/MACHINE:X86" \LD="link" \NM="dumpbin -symbols" \STRIP=":" \AR="$HOME/msvc/ar-lib lib" \RANLIB=":"makemake checkmake install elif [ "${PlatformTarget}"=="x64" ]; thenexport PATH=`cygpath -u "${VCToolsInstallDir}"`/bin/Hostx64/x64:`cygpath -u "${WindowsSdkDir}"`bin/"${WindowsSDKVersion}"/x64:"$PATH"win32_target=_WIN32_WINNT_WIN7./configure --host=x86_64-w64-mingw32 --prefix=/usr/local/msvc64 \CC="$HOME/msvc/compile cl -nologo" \CFLAGS="-MD /utf-8" \CXX="$HOME/msvc/compile cl -nologo" \CXXFLAGS="-MD /utf-8" \CPPFLAGS="-D_WIN32_WINNT=$win32_target" \RC="windres -Fpe-x86-64" \WINDRES="windres -Fpe-x86-64" \LDFLAGS="/MACHINE:X64" \LD="link" \NM="dumpbin -symbols" \STRIP=":" \AR="$HOME/msvc/ar-lib lib" \RANLIB=":"makemake checkmake install elseecho Modify PlatformTarget value and run again.exit 1 fi總結
以上是生活随笔為你收集整理的How to build libiconv with VC2017的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 太阳能自动灌溉系统 利用spwm实现逆变
- 下一篇: gpl开源协议