Mac下編譯libcurl靜態庫
18-10-01 17:56
### 1.背景 因為專案原因,需要為ios版本提供一個sdk版本,而這個sdk庫中使用到了curl,為了完成這個ios sdk,需要編譯一個ios環境下的libcurl庫。 因為libcurl庫的問題,在mac下編譯出來的32和64位版本有相容性問題,標頭檔案都有不一樣的地方,導致使用報錯。另外mac環境下的各個cpu架構的支援和真機/模擬器的區別也給sdk的工作增加了難度。 ### 2.libcurl編譯指令碼 經過各方比較後,最後[這裡](https://blog.csdn.net/yq910902/article/details/50853685)介紹的方法最有效,不過也有幾個小問題,需要做幾點修改。為了防止連結失效,將基於他修改的ios編譯指令碼如下: ``` #!/bin/sh #Automatic build script for libcurl #for iPhoneOS and iPhoneSimulator # #Created by Rockee on 2012-7-26. #Copyright 2012 Rockee. All rights reserved. # #Licensed under the Apache License, Version 2.0 (the "License"); #you may not use this file except in compliance with the License. #You may obtain a copy of the License at # #http://www.apache.org/licenses/LICENSE-2.0 # #Unless required by applicable law or agreed to in writing, software #distributed under the License is distributed on an "AS IS" BASIS, #WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #See the License for the specific language governing permissions and #limitations under the License. # ########################################################################### #Change values here# ## VERSION="7.40.0"# SDKVERSION=`xcrun -sdk iphoneos --show-sdk-version`# DEVELOPER=`xcode-select -print-path`# ARCHS="i386 x86_64 armv7 armv7s arm64"# ## ########################################################################### ## # Don't change anything under this line!# ## ########################################################################### xcodebuild -version #developer root path xcode-select -print-path #developer sdk version xcrun -sdk iphoneos --show-sdk-version xcrun -sdk iphonesimulator --show-sdk-version #developer sdk path xcrun -sdk iphoneos --show-sdk-path xcrun -sdk iphonesimulator --show-sdk-path #developer cmd path xcrun --sdk iphoneos --find gcc xcrun --sdk iphoneos --find clang++ ########################################################################### ## ## # Build oppenSSL# ## echo "##################################################################" # echo "########################## Build openSSL #########################" # ./ios-build-libssl.sh# echo "########################## Build openSSL End!#####################" # echo "##################################################################" # ## ## ########################################################################### echo "##################################################################" echo "########################## Build libcurl #########################" CURRENTPATH=$(pwd)#獲取當前目錄絕對路徑 echo "--OK!------ 當前目錄:${CURRENTPATH}" SSLPATH="${CURRENTPATH}/OpenSSL" echo "--OK!------ 第三方庫:${SSLPATH}" mkdir -p "Curl" cd "Curl" CURRENTPATH=$(pwd)#獲取當前目錄絕對路徑 echo "--OK!------ 當前目錄:${CURRENTPATH}" #判斷是否安裝Xcode.app if [ ! \( -d "$DEVELOPER" \) ] ; then echo "--ERR:------ 編譯工具:The iPhone SDK could not be found.Folder: \"$DEVELOPER\" does notexist." exit 1 else echo "--OK!------ 編譯工具:The iPhone SDK be found!!" fi set -e #判斷當前目錄下是否有curl-VERSION.tar.gz壓縮包 if [ ! -e curl-${VERSION}.tar.gz ] ; then echo "--OK!------ 下載檔案:curl-${VERSION}.tar.gz" curl -O https://curl.haxx.se/download/curl-${VERSION}.tar.gz else echo "--OK!------ 使用檔案:curl-${VERSION}.tar.gz" fi mkdir -p "${CURRENTPATH}/src" mkdir -p "${CURRENTPATH}/bin" mkdir -p "${CURRENTPATH}/lib" echo "--OK!------ 建立目錄:${CURRENTPATH}/src" echo "--OK!------ 建立目錄:${CURRENTPATH}/bin" echo "--OK!------ 建立目錄:${CURRENTPATH}/lib" tar zvxf curl-${VERSION}.tar.gz -C "${CURRENTPATH}/src"#將壓縮包解壓縮到src下 echo "--OK!------ 解壓檔案:curl-${VERSION}.tar.gz到${CURRENTPATH}/src" cd "${CURRENTPATH}/src/curl-${VERSION}"#進入到curl資料夾下 echo "--OK!------ 進入目錄:${CURRENTPATH}/src/curl-${VERSION}" #獲取當前目錄絕對路徑 BUILDPATH=$(pwd) echo "--OK!------ 當前目錄:${BUILDPATH}" for ARCH in ${ARCHS} do echo "##################BUILDIT(${ARCH} , ${ARCH})##################" export IPHONEOS_DEPLOYMENT_TARGET="7.0" export CROSS_TOP="${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer" export CROSS_SDK="${PLATFORM}${SDKVERSION}.sdk" export BUILD_TOOLS="${DEVELOPER}" if [[ "${ARCH}" == "i386" || "${ARCH}" == "x86_64" ]]; then echo "##################BUILDIT(${ARCH} , ${ARCH})##################" PLATFORM="iPhoneSimulator" SDKTYPE="iphonesimulator" export CC=$(xcrun --sdk $SDKTYPE --find gcc) export CXX=$(xcrun --sdk $SDKTYPE --find clang++) export CFLAGS="-arch ${ARCH} -pipe -Os -gdwarf-2 -isysroot $(xcrun --sdk $SDKTYPE --show-sdk-path) -mios-simulator-version-min=$IPHONEOS_DEPLOYMENT_TARGET" export LDFLAGS="-L${SSLPATH}/bin/${platform}${SDK}-${target}.sdk/lib" export PKG_CONFIG_PATH="${SSLPATH}/bin/${platform}${SDK}-${target}.sdk/lib/pkgconfig" mkdir -p "${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk" LOG="${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk/build-curl-${VERSION}.log" ./configure --without-libidn--disable-shared --enable-static --host="${ARCH}-apple-darwin" --with-ssl=$SSLPATH --prefix="${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk/" > "${LOG}" 2>&1 else PLATFORM="iPhoneOS" SDKTYPE="iphoneos" export CC=$(xcrun --sdk $SDKTYPE --find gcc) export CXX=$(xcrun --sdk $SDKTYPE --find clang++) export CFLAGS="-arch ${ARCH} -pipe -Os -gdwarf-2 -isysroot $(xcrun --sdk $SDKTYPE --show-sdk-path)-miphoneos-version-min=$IPHONEOS_DEPLOYMENT_TARGET" export LDFLAGS="-L${SSLPATH}/bin/${platform}${SDK}-${target}.sdk/lib" export PKG_CONFIG_PATH="${SSLPATH}/bin/${platform}${SDK}-${target}.sdk/lib/pkgconfig" mkdir -p "${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk" LOG="${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk/build-curl-${VERSION}.log" if [[ "${ARCH}" = "arm64" ]]; then ./configure --without-libidn--disable-shared --enable-static--enable-threaded-resolver --host="aarch64-apple-darwin" --with-ssl=$SSLPATH --prefix="${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk/" > "${LOG}" 2>&1 else ./configure --without-libidn--disable-shared --enable-static--enable-threaded-resolver --host="${ARCH}-apple-darwin" --with-ssl=$SSLPATH --prefix="${CURRENTPATH}/bin/${PLATFORM}${SDKVERSION}-${ARCH}.sdk/" > "${LOG}" 2>&1 fi fi make #make -j `sysctl -n hw.logicalcpu_max` cp lib/.libs/libcurl.a ../../bin/libcurl-${ARCH}.a make clean echo "--OK!------ Install bin/libcurl-${ARCH}.a OK!" echo "################BUILDIT(${target} , ${platform}) End!################" echo "#####################################################################" done echo "--OK!------ ############################################################" echo "--OK!------ Build library..." #歸檔公用庫 #lipo -create ${CURRENTPATH}/bin/libcurl.armv7.a ${CURRENTPATH}/bin/libcurl.i386.a -output ${CURRENTPATH}/lib/libcurl.a LIBCURL_SRC="" for ARCH in ${ARCHS} do if [[ "${ARCH}" == "i386" || "${ARCH}" == "x86_64" ]]; then LIBCURL_SRC="${LIBCURL_SRC}${CURRENTPATH}/bin/libcurl-${ARCH}.a " else LIBCURL_SRC="${LIBCURL_SRC}${CURRENTPATH}/bin/libcurl-${ARCH}.a " fi done lipo -create ${LIBCURL_SRC} -output ${CURRENTPATH}/lib/libcurl.a mkdir -p ${CURRENTPATH}/include cp -R ${BUILDPATH}/include ${CURRENTPATH}/ echo "--OK!------ Building done." echo "--OK!------ Cleaning up..." rm -rf ${CURRENTPATH}/src/curl-${VERSION} echo "--OK!------ Done." echo "--OK!------ ############################################################" ``` 修改處如下: 1. find clang 修改成 find gcc,不然會報錯 2. curl拉取官網curl原始碼包的使用改用https協議 使用以上指令碼,編譯出來的libcurl是ios全平臺包。 ### 3. array with a negative size 問題解決 由於libcurl存在32和64位編譯出來相容性問題,交叉使用可能會導致如下報錯: ``` '__curl_rule_01__' declared as an array with a negative size ``` 最後發現是需要一個整合的curlbuild.h檔案才能相容,可以直接採用[這裡](https://gist.github.com/deltheil/7fe3da9c7074fffa81cf)的curlbuild.h替換本地的對應檔案,不過注意我是用的curl7.40版本,沒測試過其他版本是否有相容性問題。 curlbuild.h內容如下: ``` /* include/curl/curlbuild.h.Generated from curlbuild.h.in by configure.*/ #ifndef __CURL_CURLBUILD_H #define __CURL_CURLBUILD_H /*************************************************************************** *__ _____ *Project___| | | |_ \| | */ __| | | | |_) | | *| (__| |_| |_ <| |___ *\___|\___/|_| \_\_____| * * Copyright (C) 1998 - 2012, Daniel Stenberg, <[email protected]>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://curl.haxx.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ***************************************************************************/ /* ================================================================ */ /*NOTES FOR CONFIGURE CAPABLE SYSTEMS*/ /* ================================================================ */ /* * NOTE 1: * ------- * * Nothing in this file is intended to be modified or adjusted by the * curl library user nor by the curl library builder. * * If you think that something actually needs to be changed, adjusted * or fixed in this file, then, report it on the libcurl development * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/ * * This header file shall only export symbols which are 'curl' or 'CURL' * prefixed, otherwise public name space would be polluted. * * NOTE 2: * ------- * * Right now you might be staring at file include/curl/curlbuild.h.in or * at file include/curl/curlbuild.h, this is due to the following reason: * * On systems capable of running the configure script, the configure process * will overwrite the distributed include/curl/curlbuild.h file with one that * is suitable and specific to the library being configured and built, which * is generated from the include/curl/curlbuild.h.in template file. * */ /* ================================================================ */ /*DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE*/ /* ================================================================ */ #ifdef CURL_SIZEOF_LONG #error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined #endif #ifdef CURL_TYPEOF_CURL_SOCKLEN_T #error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined #endif #ifdef CURL_SIZEOF_CURL_SOCKLEN_T #error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined #endif #ifdef CURL_TYPEOF_CURL_OFF_T #error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined #endif #ifdef CURL_FORMAT_CURL_OFF_T #error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined #endif #ifdef CURL_FORMAT_CURL_OFF_TU #error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined #endif #ifdef CURL_FORMAT_OFF_T #error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined #endif #ifdef CURL_SIZEOF_CURL_OFF_T #error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined #endif #ifdef CURL_SUFFIX_CURL_OFF_T #error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined #endif #ifdef CURL_SUFFIX_CURL_OFF_TU #error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h" Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined #endif /* ================================================================ */ /*EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY*/ /* ================================================================ */ #ifdef __LP64__ /* Configure process defines this to 1 when it finds out that system*/ /* header file ws2tcpip.h must be included by the external interface. */ /* #undef CURL_PULL_WS2TCPIP_H */ #ifdef CURL_PULL_WS2TCPIP_H #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> #endif /* Configure process defines this to 1 when it finds out that system*/ /* header file sys/types.h must be included by the external interface. */ #define CURL_PULL_SYS_TYPES_H 1 #ifdef CURL_PULL_SYS_TYPES_H #include <sys/types.h> #endif /* Configure process defines this to 1 when it finds out that system */ /* header file stdint.h must be included by the external interface.*/ /* #undef CURL_PULL_STDINT_H */ #ifdef CURL_PULL_STDINT_H #include <stdint.h> #endif /* Configure process defines this to 1 when it finds out that system*/ /* header file inttypes.h must be included by the external interface. */ /* #undef CURL_PULL_INTTYPES_H */ #ifdef CURL_PULL_INTTYPES_H #include <inttypes.h> #endif /* Configure process defines this to 1 when it finds out that system*/ /* header file sys/socket.h must be included by the external interface. */ #define CURL_PULL_SYS_SOCKET_H 1 #ifdef CURL_PULL_SYS_SOCKET_H #include <sys/socket.h> #endif /* Configure process defines this to 1 when it finds out that system*/ /* header file sys/poll.h must be included by the external interface. */ /* #undef CURL_PULL_SYS_POLL_H */ #ifdef CURL_PULL_SYS_POLL_H #include <sys/poll.h> #endif /* The size of `long', as computed by sizeof. */ #define CURL_SIZEOF_LONG 8 /* Integral data type used for curl_socklen_t. */ #define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t /* The size of `curl_socklen_t', as computed by sizeof. */ #define CURL_SIZEOF_CURL_SOCKLEN_T 4 /* Data type definition of curl_socklen_t. */ typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; /* Signed integral data type used for curl_off_t. */ #define CURL_TYPEOF_CURL_OFF_T long /* Data type definition of curl_off_t. */ typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; /* curl_off_t formatting string directive without "%" conversion specifier. */ #define CURL_FORMAT_CURL_OFF_T "ld" /* unsigned curl_off_t formatting string without "%" conversion specifier. */ #define CURL_FORMAT_CURL_OFF_TU "lu" /* curl_off_t formatting string directive with "%" conversion specifier. */ #define CURL_FORMAT_OFF_T "%ld" /* The size of `curl_off_t', as computed by sizeof. */ #define CURL_SIZEOF_CURL_OFF_T 8 /* curl_off_t constant suffix. */ #define CURL_SUFFIX_CURL_OFF_T L /* unsigned curl_off_t constant suffix. */ #define CURL_SUFFIX_CURL_OFF_TU UL #else/* __LP64__ */ /* Configure process defines this to 1 when it finds out that system*/ /* header file ws2tcpip.h must be included by the external interface. */ /* #undef CURL_PULL_WS2TCPIP_H */ #ifdef CURL_PULL_WS2TCPIP_H #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include <windows.h> #include <winsock2.h> #include <ws2tcpip.h> #endif /* Configure process defines this to 1 when it finds out that system*/ /* header file sys/types.h must be included by the external interface. */ #define CURL_PULL_SYS_TYPES_H 1 #ifdef CURL_PULL_SYS_TYPES_H #include <sys/types.h> #endif /* Configure process defines this to 1 when it finds out that system */ /* header file stdint.h must be included by the external interface.*/ #define CURL_PULL_STDINT_H 1 #ifdef CURL_PULL_STDINT_H #include <stdint.h> #endif /* Configure process defines this to 1 when it finds out that system*/ /* header file inttypes.h must be included by the external interface. */ #define CURL_PULL_INTTYPES_H 1 #ifdef CURL_PULL_INTTYPES_H #include <inttypes.h> #endif /* Configure process defines this to 1 when it finds out that system*/ /* header file sys/socket.h must be included by the external interface. */ #define CURL_PULL_SYS_SOCKET_H 1 #ifdef CURL_PULL_SYS_SOCKET_H #include <sys/socket.h> #endif /* Configure process defines this to 1 when it finds out that system*/ /* header file sys/poll.h must be included by the external interface. */ /* #undef CURL_PULL_SYS_POLL_H */ #ifdef CURL_PULL_SYS_POLL_H #include <sys/poll.h> #endif /* The size of `long', as computed by sizeof. */ #define CURL_SIZEOF_LONG 4 /* Integral data type used for curl_socklen_t. */ #define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t /* The size of `curl_socklen_t', as computed by sizeof. */ #define CURL_SIZEOF_CURL_SOCKLEN_T 4 /* Data type definition of curl_socklen_t. */ typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; /* Signed integral data type used for curl_off_t. */ #define CURL_TYPEOF_CURL_OFF_T int64_t /* Data type definition of curl_off_t. */ typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; /* curl_off_t formatting string directive without "%" conversion specifier. */ #define CURL_FORMAT_CURL_OFF_T "lld" /* unsigned curl_off_t formatting string without "%" conversion specifier. */ #define CURL_FORMAT_CURL_OFF_TU "llu" /* curl_off_t formatting string directive with "%" conversion specifier. */ #define CURL_FORMAT_OFF_T "%lld" /* The size of `curl_off_t', as computed by sizeof. */ #define CURL_SIZEOF_CURL_OFF_T 8 /* curl_off_t constant suffix. */ #define CURL_SUFFIX_CURL_OFF_T LL /* unsigned curl_off_t constant suffix. */ #define CURL_SUFFIX_CURL_OFF_TU ULL #endif /* __LP64__ */ #endif /* __CURL_CURLBUILD_H */ ``` 如此編譯好libcurl.a庫檔案, 且替換好curlbuild.h後,即可新增到自己的xcode工程中使用。 ### 4.array with a negative size問題的另外一個解決嘗試 另外 問題也可以採用如下方式嘗試解決: 在curlbuild.h檔案中,將以下程式碼: ``` #define CURL_SIZEOF_LONG 4 ``` 替換成 ``` #ifdef __arch64__ #define CURL_SIZEOF_LONG 8 #else #define CURL_SIZEOF_LONG 4 #endif ``` ### 5.libcurl另外的編譯指令碼選擇 有2個另外的編譯指令碼看起來靠譜,但是未測試過,如下: 1. https://raw.githubusercontent.com/sinofool/build-libcurl-ios/master/build_libcurl_dist.sh 2. https://raw.githubusercontent.com/fenglc/build-libcurl-for-ios/master/build.sh