How do I include libxslt in my iPhone app?
I've heard that including libxslt.dylib is grounds for getting your app rejected. I don't know how accurate that is.
Nevertheless, I would like to include the latest version of libxslt. I'开发者_开发问答d like to do the same thing with libxml2, as well as other libraries in the future.
What is the correct way to include a code library like this in my app?
My app was rejected with the following message from Apple.
XYZ app cannot be posted to the App Store because it is using private or undocumented APIs:
Private Symbol References xsltApplyStylesheet xsltCleanupGlobals xsltFreeStylesheet xsltInit xsltParseStylesheetFile xsltSaveResultToString
As you know, as outlined in the iPhone Developer Program License Agreement section 3.3.1, the use of non-public APIs is not permitted. Before your application can be reviewed by the App Review Team, please resolve this issue and upload a new binary to iTunes Connect.
It was my understanding that the libxslt and libxml2 libraries were in fact present on the device and are available via the pull down menu in Xcode. I dynamically link link with these two libraries and my app works beautifully on the device. Hence, the libraries must be on the device. Why would I need to build these libraries from scratch as static libraries and increase the size of my app?
I can't find any clear way to work around this, aside from not using xml and xslt. That makes no sense at all!
Hilton, have you succeeded in submitting an app to iTunes that uses xslt?
I finally got libxslt to build in Xcode, link to my app, and evade the app store rejectionbot.
Basically you have to build libxslt statically and change the symbol names so they don't match the ones that Apple looks for. All symbols xsltFoo()
must be changed to zsltFoo()
. Also the name of the library itself must be changed from libxslt.a
to libzslt.a
.
Here's a how to do it in 10 easy steps :)
- Create a
libxslt
subdirectory and putlibxslt-1.1.26.tar.gz
into it. - Right click on Target -> YourApp and select Add -> New Build Phase -> New Run Script Build Phase
- Copy the build script below
- Rename the the build phase from "Run Script" to "Build libxslt" and make it first in the list
- Build your project, which will cause
libxslt
to be configured and built and installed inlibxslt/dist
- Right click on Frameworks and select Add -> Existing Files... and then select
libxslt/dist/lib/libzslt.a
- Go to Project -> Edit Project Settings -> Build
- Under Search Paths, edit Header Search Paths and add
libxslt/dist/include
- Add
#include <libxslt/whatever.h>
to your code as needed normally - Use
zsltFoo
instead ofxsltFoo
everywhere in your code
Here is the libxslt
build script referenced in step #3:
#!/bin/sh
# Setup
LIBXSLT_VERSION="1.1.26"
LIBXSLT_SHA1_CHECKSUM="69f74df8228b504a87e2b257c2d5238281c65154"
GCC_VERSION="4.2.1"
ARCH="arm-apple-darwin10"
# Bail on any error
set -e
# Function that patches a file using sed(1).
# First argument is filename, subsequent arguments are passed to sed(1).
sed_patch_file()
{
FILE="${1}"
shift
sed ${1+"$@"} < "${FILE}" > "${FILE}".new
if ! diff -q "${FILE}" "${FILE}".new >/dev/null; then
cat "${FILE}".new > "${FILE}"
fi
rm "${FILE}".new
}
# Function that displays the command and then executes it
show_cmd()
{
echo ${1+"$@"}
${1+"$@"}
}
# Dump environment variables
#echo '***************************************************'
#env | sort
#echo '***************************************************'
# Files
SRCBALL="${SOURCE_ROOT}/libxslt/libxslt-${LIBXSLT_VERSION}.tar.gz"
SRCDIR="${SOURCE_ROOT}/libxslt/libxslt-${LIBXSLT_VERSION}"
DISTDIR="${SOURCE_ROOT}/libxslt/dist"
# Verify source is installed
if ! [ -f "${SRCBALL}" ]; then
echo "ERROR: please download and install ${SRCBALL}" 2>&1
echo "The SHA1 checksum should be: ${LIBXSLT_SHA1_CHECKSUM}" 2>&1
exit 1
fi
# Unpack the archive if necessary
if ! [ -e "${SRCDIR}" ]; then
# Unpack archive
echo "*** Unpacking archive ${SRCBALL}"
tar zxf "${SRCBALL}" -C libxslt
# Rename all symbols xsltFoobar -> zsltFoobar to avoid broken app store link analyzer
echo "*** Changing symbol names"
find libxslt/libxslt-"${LIBXSLT_VERSION}" -name '*.[ch]' -print | while read FILE; do
sed_patch_file "${FILE}" -E 's%([^[:alnum:]_/"]|^)xslt([A-Z])%\1zslt\2%g'
done
# Disable build of xsltproc which fails to link
sed_patch_file libxslt/libxslt-"${LIBXSLT_VERSION}"/Makefile.in -E '/^[[:space:]]xsltproc \\$/d'
fi
# Build and install
if ! [ -e "${DISTDIR}" ]; then
# Set up autoconf environment variables
export CPP="${PLATFORM_DEVELOPER_BIN_DIR}/${ARCH}-gcc-${GCC_VERSION} -E"
export CC="${PLATFORM_DEVELOPER_BIN_DIR}/${ARCH}-gcc-${GCC_VERSION}"
export CXX="${PLATFORM_DEVELOPER_BIN_DIR}/${ARCH}-g++-${GCC_VERSION}"
export CPPFLAGS="-I${SDKROOT}/usr/lib/gcc/${ARCH}/${GCC_VERSION}/include -I${SDKROOT}/usr/include"
export LDFLAGS="--sysroot=${SDKROOT}"
export CFLAGS="-Os -pipe ${CPPFLAGS} ${LDFLAGS}"
export CXXFLAGS="${CFLAGS}"
export ARCH
# Configure libxslt
echo "*** Configuring libxslt-${LIBXSLT_VERSION}"
( cd "${SRCDIR}" && show_cmd ./configure \
--prefix="${DISTDIR}" \
--build=i386-apple-darwin10 \
--host="${ARCH}" \
--enable-static \
--disable-shared \
--with-libxml-include-prefix="${SDKROOT}"/usr/include \
--with-libxml-libs-prefix="${SDKROOT}"/usr/lib \
--without-python )
# Build it
echo "*** Building libxslt-${LIBXSLT_VERSION}"
( cd "${SRCDIR}" && show_cmd make )
# Install it
echo "*** Installing libxslt-${LIBXSLT_VERSION}"
( cd "${SRCDIR}" && show_cmd make install )
# Change library name to avoid dynamic linking to the iPhone's shared libxslt library
ln libxslt/dist/lib/lib{x,z}slt.a
fi
Hey Hilton, any chance you could let us know how you managed to statically link the LIBXSLT library into your app please?
I'm having exactly the same issue as quite a few others but at the moment at least, I have no idea how to go about turning the dynamic library into a static one.
Thanks.
EDIT: Check out this Version of XSLT in iPhone
My app was rejected for using LibXSLT so instead I manually added the source code and did it that way. My app was approved a few days ago.
You can only dynamically link to libraries that are already present on the device.
If you want to link to an external library that is not present on the device, you will have to compile it yourself to a static library and link that instead.
Based on Archie's answer, this script (with XCode 5 command line tools) generates a multi-architecture libzslt suitable for inclusion in a project, compatible with iOS 6 and iOS 7 projects (though I haven't included iOS 7 64 bit).
This solution assumes libxslt-1.1.28 is unpacked and in the same directory as the script.
The script creates a directory dependencies which contains the header and lib files. You can include them in an Xcode project by adjusting the header and linker search paths.
#!/bin/sh
# build.sh
GLOBAL_OUTDIR="`pwd`/dependencies"
LOCAL_OUTDIR="outdir"
XSLT_LIB="`pwd`/libxslt-1.1.28"
IOS_BASE_SDK="7.0"
IOS_DEPLOY_TGT="6.0"
sed_patch_file()
{
FILE="${1}"
shift
sed ${1+"$@"} "${FILE}".new
if ! diff -q "${FILE}" "${FILE}".new >/dev/null; then
cat "${FILE}".new > "${FILE}"
fi
rm "${FILE}".new
}
patch_libxslt() {
export LIBXSLT_VERSION=1.1.28
echo "*** Changing symbol names"
find libxslt-"${LIBXSLT_VERSION}" -name '*.[ch]' -print | while read FILE; do
sed_patch_file "${FILE}" -E 's%([^[:alnum:]_/"]|^)xslt([A-Z])%\1zslt\2%g'
done
# Disable build of xsltproc which fails to link
sed_patch_file libxslt-"${LIBXSLT_VERSION}"/Makefile.in -E '/^[[:space:]]xsltproc \\$/d'
}
setenv_all()
{
unset LIBRARIES
export LIBRARIES=${SDKROOT}/usr/lib
echo "*** LIBRARIES: ${LIBRARIES}"
# Add internal libs
export LDFLAGS="--sysroot=${SDKROOT} $LDFLAGS -L${LIBRARIES}"
export CFLAGS="--sysroot=${SDKROOT} $CFLAGS -I${SDKROOT}/usr/lib/gcc/${ARCH}/${GCC_VERSION}/include -I${SDKROOT}/usr/include -arch ${ARCH} -Os -pipe ${CPPFLAGS}"
export CXX="$PLATFORM_BIN_DIR/g++"
export CC="$PLATFORM_BIN_DIR/gcc"
export LD=$TOOLROOT/ld
export AR=$TOOLROOT/ar
export AS=$TOOLROOT/as
export NM=$TOOLROOT/nm
export RANLIB=$TOOLROOT/ranlib
export CPPFLAGS=$CFLAGS
export CXXFLAGS=$CFLAGS
export CXXFLAGS="${CFLAGS}"
}
setenv_arm7()
{
unset LN DEVROOT SDKROOT CFLAGS CC LD CPP CXX AR AS NM CXXCPP RANLIB LDFLAGS CPPFLAGS CXXFLAGS DYLD_LIBRARY_PATH ARCH PLATFORM_BIN_DIR TOOLROOT DISTDIR
export ARCH=armv7
export DEVROOT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer
export SDKROOT=$DEVROOT/SDKs/iPhoneOS$IOS_BASE_SDK.sdk
export PLATFORM_BIN_DIR=/Applications/Xcode.app/Contents/Developer/usr/bin
export TOOLROOT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin
export DYLD_LIBRARY_PATH="$SDKROOT/usr/lib"
export CFLAGS="-arch armv7 -pipe -no-cpp-precomp -isysroot $SDKROOT -miphoneos-version-min=$IOS_DEPLOY_TGT -I$SDKROOT/usr/include/"
setenv_all
}
setenv_arm7s()
{
unset LN DEVROOT SDKROOT CFLAGS CC LD CPP CXX AR AS NM CXXCPP RANLIB LDFLAGS CPPFLAGS CXXFLAGS DYLD_LIBRARY_PATH ARCH PLATFORM_BIN_DIR TOOLROOT DISTDIR
export ARCH=armv7s
export DEVROOT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer
export SDKROOT=$DEVROOT/SDKs/iPhoneOS$IOS_BASE_SDK.sdk
export PLATFORM_BIN_DIR=/Applications/Xcode.app/Contents/Developer/usr/bin
export TOOLROOT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin
export DYLD_LIBRARY_PATH="$SDKROOT/usr/lib"
export CFLAGS="-arch armv7s -pipe -no-cpp-precomp -isysroot $SDKROOT -miphoneos-version-min=$IOS_DEPLOY_TGT -I$SDKROOT/usr/include/"
setenv_all
}
setenv_i386()
{
unset LN DEVROOT SDKROOT CFLAGS CC LD CPP CXX AR AS NM CXXCPP RANLIB LDFLAGS CPPFLAGS CXXFLAGS DYLD_LIBRARY_PATH ARCH PLATFORM_BIN_DIR TOOLROOT DISTDIR
export ARCH=i386
export DEVROOT=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer
export SDKROOT=$DEVROOT/SDKs/iPhoneSimulator$IOS_BASE_SDK.sdk
export PLATFORM_BIN_DIR=$DEVROOT/usr/bin
export TOOLROOT=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
export CFLAGS="-arch i386 -pipe -no-cpp-precomp -isysroot $SDKROOT -miphoneos-version-min=$IOS_DEPLOY_TGT"
setenv_all
}
create_outdir_lipo()
{
for lib_i386 in `find $LOCAL_OUTDIR/i386 -name "lib*\.a"`; do
lib_arm7=`echo $lib_i386 | sed "s/i386/arm7/g"`
lib_arm7s=`echo $lib_i386 | sed "s/i386/arm7s/g"`
lib=`echo $lib_i386 | sed "s/i386\///g"`
mkdir -p $(dirname $lib)
cmd="xcrun -sdk iphoneos lipo -arch armv7 $lib_arm7 -arch i386 $lib_i386 -arch armv7s $lib_arm7s -create -output $lib"
echo $cmd
$cmd
done
}
merge_libfiles()
{
DIR=$1
LIBNAME=$2
cd $DIR
for i in `find . -name "lib*.a"`; do
$AR -x $i
done
$AR -r $LIBNAME *.o
rm -rf *.o __*
cd -
}
#######################
# libxslt
#######################
patch_libxslt
cd $XSLT_LIB
rm -rf $LOCAL_OUTDIR
mkdir -p $LOCAL_OUTDIR/arm7 $LOCAL_OUTDIR/i386
make clean 2> /dev/null
setenv_i386
export DISTDIR=`pwd`/$LOCAL_OUTDIR/i386
./configure --prefix="${DISTDIR}" \
--enable-static \
--disable-shared \
--with-libxml-include-prefix="${SDKROOT}"/usr/include \
--with-libxml-libs-prefix="${SDKROOT}"/usr/lib \
--without-crypto \
--without-python || exit
make "CC=$CC" "CFLAGS=$CFLAGS" "AR=$AR"
make install
ln $LOCAL_OUTDIR/i386/lib/lib{x,z}slt.a
# find ./ -iname *.a | grep -v $LOCAL_OUTDIR | xargs -L 1 -I '{}' cp '{}' $LOCAL_OUTDIR/i386
# cp -vf lib*.a $LOCAL_OUTDIR/i386
make clean 2> /dev/null
setenv_arm7
export DISTDIR=`pwd`/$LOCAL_OUTDIR/arm7
./configure --prefix="${DISTDIR}" \
--host=armv7-apple-darwin12.5.0 \
--enable-static \
--disable-shared \
--with-libxml-include-prefix="${SDKROOT}"/usr/include \
--with-libxml-libs-prefix="${SDKROOT}"/usr/lib \
--without-crypto \
--without-python || exit
make -j4
make install
ln $LOCAL_OUTDIR/arm7/lib/lib{x,z}slt.a
# find ./ -iname *.a | grep -v $LOCAL_OUTDIR | xargs -L 1 -I '{}' cp '{}' $LOCAL_OUTDIR/arm7
# cp -rvf lib*.a $LOCAL_OUTDIR/arm7
make clean 2> /dev/null
setenv_arm7s
export DISTDIR=`pwd`/$LOCAL_OUTDIR/arm7s
./configure --prefix="${DISTDIR}" \
--host=armv7s-apple-darwin12.5.0 \
--enable-static \
--disable-shared \
--with-libxml-include-prefix="${SDKROOT}"/usr/include \
--with-libxml-libs-prefix="${SDKROOT}"/usr/lib \
--without-crypto \
--without-python || exit
make -j4
make install
ln $LOCAL_OUTDIR/arm7s/lib/lib{x,z}slt.a
# find ./ -iname *.a | grep -v $LOCAL_OUTDIR | xargs -L 1 -I '{}' cp '{}' $LOCAL_OUTDIR/arm7s
# cp -rvf lib*.a $LOCAL_OUTDIR/arm7s
create_outdir_lipo
mkdir -p $GLOBAL_OUTDIR/lib && cp -rvf $LOCAL_OUTDIR/lib/lib*.a $GLOBAL_OUTDIR/lib
mkdir -p $GLOBAL_OUTDIR/include && cp -rvf $LOCAL_OUTDIR/arm7/include/* $GLOBAL_OUTDIR/include
cd ..
echo "Finished!"
精彩评论