ios: Add extras/package/ios.
authorPierre d'Herbemont <pdherbemont@free.fr>
Sun, 31 Oct 2010 20:02:49 +0000 (21:02 +0100)
committerPierre d'Herbemont <pdherbemont@free.fr>
Sun, 31 Oct 2010 20:04:03 +0000 (21:04 +0100)
You can now build your iOS libvlc with build_for_iOS.sh.

extras/package/ios/build_for_iOS.sh [new file with mode: 0755]
extras/package/ios/resources/gas-preprocessor.pl [new file with mode: 0755]

diff --git a/extras/package/ios/build_for_iOS.sh b/extras/package/ios/build_for_iOS.sh
new file mode 100755 (executable)
index 0000000..05b4f3a
--- /dev/null
@@ -0,0 +1,157 @@
+#!/bin/sh
+set -e
+
+echo "Building libvlc for the iOS"
+
+if [ "$1" = "Simulator" ]; then
+    PLATFORM="Simulator"
+    TARGET="i686-apple-darwin10"
+    ARCH="i386"
+else
+    PLATFORM="OS"
+    TARGET="arm-apple-darwin10"
+    ARCH="armv7"
+    OPTIM="-mno-thumb"
+fi
+
+THIS_SCRIPT_PATH=`pwd`/$0
+
+pushd `dirname $0`/../../.. > /dev/null
+VLCROOT=`pwd` # Let's make sure VLCROOT is an absolute path
+popd > /dev/null
+DEVROOT="/Developer/Platforms/iPhone${PLATFORM}.platform/Developer"
+IOS_SDK_ROOT="${DEVROOT}/SDKs/iPhone${PLATFORM}4.2.sdk"
+
+BUILDDIR="${VLCROOT}/build-ios-${PLATFORM}"
+
+PREFIX="${VLCROOT}/install-ios-${PLATFORM}"
+
+IOS_GAS_PREPROCESSOR="${VLCROOT}/extras/package/ios/resources/gas-preprocessor.pl"
+
+export AR="${DEVROOT}/usr/bin/ar"
+export RANLIB="${DEVROOT}/usr/bin/ranlib"
+export CFLAGS="-isysroot ${IOS_SDK_ROOT} -arch ${ARCH} -miphoneos-version-min=3.2 ${OPTIM}"
+export OBJCFLAGS="${CFLAGS}"
+if [ "$PLATFORM" = "Simulator" ]; then
+    # Use the new ABI on simulator, else we can't build
+    export OBJCFLAGS="-fobjc-abi-version=2 -fobjc-legacy-dispatch ${OBJCFLAGS}"
+fi
+export CPPFLAGS="${CFLAGS}"
+export CXXFLAGS="${CFLAGS}"
+export CPP="${DEVROOT}/usr/bin/cpp-4.2"
+export CXXCPP="${DEVROOT}/usr/bin/cpp-4.2"
+
+export CC="${DEVROOT}/usr/bin/gcc-4.2"
+export OBJC="${DEVROOT}/usr/bin/gcc-4.2"
+export CXX="${DEVROOT}/usr/bin/g++-4.2"
+export LD="${DEVROOT}/usr/bin/ld"
+export STRIP="${DEVROOT}/usr/bin/strip"
+
+if [ "$PLATFORM" = "OS" ]; then
+  export LDFLAGS="-L${IOS_SDK_ROOT}/usr/lib -arch ${ARCH}"
+else
+  export LDFLAGS="-syslibroot=${IOS_SDK_ROOT}/ -arch ${ARCH}"
+fi
+
+export PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin:${VLCROOT}/extras/contrib/build/bin:${VLCROOT}/extras/package/ios/resources"
+
+echo "Boostraping contribs"
+pushd ${VLCROOT}/extras/contrib > /dev/null
+
+# contains gas-processor.pl
+export PATH=$PATH:${VLCROOT}/extras/package/ios/resources
+
+# The contrib will read the following
+export IOS_SDK_ROOT
+
+echo "Building contrib for iOS"
+./bootstrap -t ${TARGET} -d ios \
+   -b "${VLCROOT}/contrib-builddir-ios-${TARGET}" \
+   -i "${VLCROOT}/contrib-ios-${TARGET}"
+pushd "${VLCROOT}/contrib-builddir-ios-${TARGET}" > /dev/null
+make src
+popd > /dev/null
+
+echo "Building contrib for current host"
+./bootstrap
+make
+
+popd
+
+if [ "$PLATFORM" = "OS" ]; then
+  export AS="${IOS_GAS_PREPROCESSOR} ${CC}"
+  export ASCPP="${IOS_GAS_PREPROCESSOR} ${CC}"
+else
+  export AS="${DEVROOT}/usr/bin/as"
+  export ASCPP="${DEVROOT}/usr/bin/as"
+fi
+
+
+echo "Bootstraping vlc"
+if ! [ -e ${VLCROOT}/configure ]; then
+    ${VLCROOT}/bootstrap
+fi
+
+if [ ".$PLATFORM" != ".Simulator" ]; then
+    # FIXME - Do we still need this?
+    export AVCODEC_CFLAGS="-I${PREFIX}/include"
+    export AVCODEC_LIBS="-L${PREFIX}/lib -lavcodec -lavutil -lz"
+    export AVFORMAT_CFLAGS="-I${PREFIX}/include"
+    export AVFORMAT_LIBS="-L${PREFIX}/lib -lavcodec -lz -lavutil -lavformat"
+fi
+
+mkdir -p ${BUILDDIR}
+pushd ${BUILDDIR}
+
+# Run configure only upon changes.
+if [ "${VLCROOT}/configure" -nt config.log -o \
+     "${THIS_SCRIPT_PATH}" -nt config.log ]; then
+CONTRIB_DIR=${VLCROOT}/contrib-ios-${TARGET} \
+${VLCROOT}/configure \
+    --prefix="${PREFIX}" \
+    --host="${TARGET}" \
+    --enable-debug \
+    --enable-static-modules \
+    --disable-macosx \
+    --disable-macosx-defaults \
+    --disable-macosx-vout \
+    --disable-macosx-dialog-provider \
+    --disable-macosx-qtcapture \
+    --disable-macosx-eyetv \
+    --disable-macosx-vlc-app \
+    --with-macosx-sdk=${IO_SDK_ROOT} \
+    --enable-audioqueue \
+    --enable-ios-vout \
+    --enable-avcodec \
+    --enable-avformat \
+    --enable-swscale \
+    --enable-faad \
+    --disable-mad \
+    --disable-a52 \
+    --disable-fribidi \
+    --disable-macosx-audio \
+    --disable-qt4 --disable-skins2 \
+    --disable-libgcrypt \
+    --disable-remoteosd \
+    --disable-vcd \
+    --disable-postproc \
+    --disable-vlc \
+    --disable-vlm \
+    --disable-httpd \
+    --disable-nls \
+    --disable-glx \
+    --disable-visual \
+    --disable-lua \
+    --disable-sse \
+    --disable-neon \
+    --disable-mmx # MMX and SSE support requires llvm which is broken on Simulator
+fi
+
+CORE_COUNT=`sysctl -n machdep.cpu.core_count`
+let MAKE_JOBS=$CORE_COUNT+1
+
+echo "Running make -j$MAKE_JOBS"
+
+make -j$MAKE_JOBS
+make install
+popd
diff --git a/extras/package/ios/resources/gas-preprocessor.pl b/extras/package/ios/resources/gas-preprocessor.pl
new file mode 100755 (executable)
index 0000000..febfd70
--- /dev/null
@@ -0,0 +1,284 @@
+#!/usr/bin/env perl
+# by David Conrad
+# This code is licensed under GPLv2 or later; go to gnu.org to read it
+#  (not that it much matters for an asm preprocessor)
+# usage: set your assembler to be something like "perl gas-preprocessor.pl gcc"
+use strict;
+
+# Apple's gas is ancient and doesn't support modern preprocessing features like
+# .rept and has ugly macro syntax, among other things. Thus, this script
+# implements the subset of the gas preprocessor used by x264 and ffmpeg
+# that isn't supported by Apple's gas.
+
+my @gcc_cmd = @ARGV;
+my @preprocess_c_cmd;
+
+if (grep /\.c$/, @gcc_cmd) {
+    # C file (inline asm?) - compile
+    @preprocess_c_cmd = (@gcc_cmd, "-S");
+} elsif (grep /\.[sS]$/, @gcc_cmd) {
+    # asm file, just do C preprocessor
+    @preprocess_c_cmd = (@gcc_cmd, "-E");
+} else {
+    die "Unrecognized input filetype";
+}
+@gcc_cmd = map { /\.[csS]$/ ? qw(-x assembler -) : $_ } @gcc_cmd;
+@preprocess_c_cmd = map { /\.o$/ ? "-" : $_ } @preprocess_c_cmd;
+
+open(ASMFILE, "-|", @preprocess_c_cmd) || die "Error running preprocessor";
+
+my $current_macro = '';
+my $macro_level = 0;
+my %macro_lines;
+my %macro_args;
+my %macro_args_default;
+
+my @pass1_lines;
+
+# pass 1: parse .macro
+# note that the handling of arguments is probably overly permissive vs. gas
+# but it should be the same for valid cases
+while (<ASMFILE>) {
+    # comment out unsupported directives
+    s/\.type/@.type/x;
+    s/\.func/@.func/x;
+    s/\.endfunc/@.endfunc/x;
+    s/\.ltorg/@.ltorg/x;
+    s/\.size/@.size/x;
+    s/\.fpu/@.fpu/x;
+
+    # the syntax for these is a little different
+    s/\.global/.globl/x;
+    # also catch .section .rodata since the equivalent to .const_data is .section __DATA,__const
+    s/(.*)\.rodata/.const_data/x;
+    s/\.int/.long/x;
+    s/\.float/.single/x;
+
+    # catch unknown section names that aren't mach-o style (with a comma)
+    if (/.section ([^,]*)$/) {
+        die ".section $1 unsupported; figure out the mach-o section name and add it";
+    }
+
+    parse_line($_);
+}
+
+sub parse_line {
+    my $line = @_[0];
+
+    if (/\.macro/) {
+        $macro_level++;
+        if ($macro_level > 1 && !$current_macro) {
+            die "nested macros but we don't have master macro";
+        }
+    } elsif (/\.endm/) {
+        $macro_level--;
+        if ($macro_level < 0) {
+            die "unmatched .endm";
+        } elsif ($macro_level == 0) {
+            $current_macro = '';
+            return;
+        }
+    }
+
+    if ($macro_level > 1) {
+        push(@{$macro_lines{$current_macro}}, $line);
+    } elsif ($macro_level == 0) {
+        expand_macros($line);
+    } else {
+        if (/\.macro\s+([\d\w\.]+)\s*(.*)/) {
+            $current_macro = $1;
+
+            # commas in the argument list are optional, so only use whitespace as the separator
+            my $arglist = $2;
+            $arglist =~ s/,/ /g;
+
+            my @args = split(/\s+/, $arglist);
+            foreach my $i (0 .. $#args) {
+                my @argpair = split(/=/, $args[$i]);
+                $macro_args{$current_macro}[$i] = $argpair[0];
+                $argpair[0] =~ s/:vararg$//;
+                $macro_args_default{$current_macro}{$argpair[0]} = $argpair[1];
+            }
+            # ensure %macro_lines has the macro name added as a key
+            $macro_lines{$current_macro} = [];
+
+        } elsif ($current_macro) {
+            push(@{$macro_lines{$current_macro}}, $line);
+        } else {
+            die "macro level without a macro name";
+        }
+    }
+}
+
+sub expand_macros {
+    my $line = @_[0];
+
+    if (/\.purgem\s+([\d\w\.]+)/) {
+        delete $macro_lines{$1};
+        delete $macro_args{$1};
+        delete $macro_args_default{$1};
+        return;
+    }
+
+    if ($line =~ /(\S+:|)\s*([\w\d\.]+)\s*(.*)/ && exists $macro_lines{$2}) {
+        push(@pass1_lines, $1);
+        my $macro = $2;
+
+        # commas are optional here too, but are syntactically important because
+        # parameters can be blank
+        my @arglist = split(/,/, $3);
+        my @args;
+        foreach (@arglist) {
+            my @whitespace_split = split(/\s+/, $_);
+            if (!@whitespace_split) {
+                push(@args, '');
+            } else {
+                foreach (@whitespace_split) {
+                    if (length($_)) {
+                        push(@args, $_);
+                    }
+                }
+            }
+        }
+
+        my %replacements;
+        if ($macro_args_default{$macro}){
+            %replacements = %{$macro_args_default{$macro}};
+        }
+
+        # construct hashtable of text to replace
+        foreach my $i (0 .. $#args) {
+            my $argname = $macro_args{$macro}[$i];
+
+            if ($args[$i] =~ m/=/) {
+                # arg=val references the argument name
+                # XXX: I'm not sure what the expected behaviour if a lot of
+                # these are mixed with unnamed args
+                my @named_arg = split(/=/, $args[$i]);
+                $replacements{$named_arg[0]} = $named_arg[1];
+            } elsif ($i > $#{$macro_args{$macro}}) {
+                # more args given than the macro has named args
+                # XXX: is vararg allowed on arguments before the last?
+                $argname = $macro_args{$macro}[-1];
+                if ($argname =~ s/:vararg$//) {
+                    $replacements{$argname} .= ", $args[$i]";
+                } else {
+                    die "Too many arguments to macro $macro";
+                }
+            } else {
+                $argname =~ s/:vararg$//;
+                $replacements{$argname} = $args[$i];
+            }
+        }
+
+        # apply replacements as regex
+        foreach (@{$macro_lines{$macro}}) {
+            my $macro_line = $_;
+            # do replacements by longest first, this avoids wrong replacement
+            # when argument names are subsets of each other
+            foreach (reverse sort {length $a <=> length $b} keys %replacements) {
+                $macro_line =~ s/\\$_/$replacements{$_}/g;
+            }
+            $macro_line =~ s/\\\(\)//g;     # remove \()
+            parse_line($macro_line);
+        }
+    } else {
+        push(@pass1_lines, $line);
+    }
+}
+
+close(ASMFILE) or exit 1;
+open(ASMFILE, "|-", @gcc_cmd) or die "Error running assembler";
+
+my @sections;
+my $num_repts;
+my $rept_lines;
+
+my %literal_labels;     # for ldr <reg>, =<expr>
+my $literal_num = 0;
+
+# pass 2: parse .rept and .if variants
+# NOTE: since we don't implement a proper parser, using .rept with a
+# variable assigned from .set is not supported
+foreach my $line (@pass1_lines) {
+    # textual comparison .if
+    # this assumes nothing else on the same line
+    if ($line =~ /\.ifnb\s+(.*)/) {
+        if ($1) {
+            $line = ".if 1\n";
+        } else {
+            $line = ".if 0\n";
+        }
+    } elsif ($line =~ /\.ifb\s+(.*)/) {
+        if ($1) {
+            $line = ".if 0\n";
+        } else {
+            $line = ".if 1\n";
+        }
+    } elsif ($line =~ /\.ifc\s+(.*)\s*,\s*(.*)/) {
+        if ($1 eq $2) {
+            $line = ".if 1\n";
+        } else {
+            $line = ".if 0\n";
+        }
+    }
+
+    # handle .previous (only with regard to .section not .subsection)
+    if ($line =~ /\.(section|text|const_data)/) {
+        push(@sections, $line);
+    } elsif ($line =~ /\.previous/) {
+        if (!$sections[-2]) {
+            die ".previous without a previous section";
+        }
+        $line = $sections[-2];
+        push(@sections, $line);
+    }
+
+    # handle ldr <reg>, =<expr>
+    if ($line =~ /(.*)\s*ldr([\w\s\d]+)\s*,\s*=(.*)/) {
+        my $label = $literal_labels{$3};
+        if (!$label) {
+            $label = ".Literal_$literal_num";
+            $literal_num++;
+            $literal_labels{$3} = $label;
+        }
+        $line = "$1 ldr$2, $label\n";
+    } elsif ($line =~ /\.ltorg/) {
+        foreach my $literal (keys %literal_labels) {
+            $line .= "$literal_labels{$literal}:\n .word $literal\n";
+        }
+        %literal_labels = ();
+    }
+
+    # @l -> lo16()  @ha -> ha16()
+    $line =~ s/,\s+([^,]+)\@l(\s)/, lo16($1)$2/g;
+    $line =~ s/,\s+([^,]+)\@ha(\s)/, ha16($1)$2/g;
+
+    if ($line =~ /\.rept\s+(.*)/) {
+        $num_repts = $1;
+        $rept_lines = "\n";
+
+        # handle the possibility of repeating another directive on the same line
+        # .endr on the same line is not valid, I don't know if a non-directive is
+        if ($num_repts =~ s/(\.\w+.*)//) {
+            $rept_lines .= "$1\n";
+        }
+        $num_repts = eval($num_repts);
+    } elsif ($line =~ /\.endr/) {
+        for (1 .. $num_repts) {
+            print ASMFILE $rept_lines;
+        }
+        $rept_lines = '';
+    } elsif ($rept_lines) {
+        $rept_lines .= $line;
+    } else {
+        print ASMFILE $line;
+    }
+}
+
+print ASMFILE ".text\n";
+foreach my $literal (keys %literal_labels) {
+    print ASMFILE "$literal_labels{$literal}:\n .word $literal\n";
+}
+
+close(ASMFILE) or exit 1;