14

How do I configure and build ICU so I can link it to my iPhone app?

I'm maintaining an iPhone app that uses a SQLite database. Now I have to compile with ICU support enabled (SQLITE_ENABLE_ICU). I've got the latest ICU source.

The configure flags I'm using:

./configure --target=arm-apple-darwin --enable-static --disable-shared

After that, running gnumake runs without errors.

Then I add the libraries to my Xcode project. But when I build, I get 50 lines of this:

Undefined symbols:
  "_uregex_close_48", referenced from:
      _icuRegexpDelete in libsqlite3-cerod.a(sqlite3_cerod.o)
  "_ubrk_current_48", referenced from:
      _icuNext in libsqlite3-cerod.a(sqlite3_cerod.o)
  "_ucol_strcoll_48", referenced from:
      _icuCollationColl in libsqlite3-cerod.a(sqlite3_cerod.o)
  "_u_isspace_48", referenced from:
      _icuRegexpFunc in libsqlite3-cerod.a(sqlite3_cerod.o)
  "_utf8_countTrailBytes_48", referenced from:
      _utf8_countTrailBytes_48$non_lazy_ptr in libsqlite3-cerod.a(sqlite3_cerod.o)
     (maybe you meant: _utf8_countTrailBytes_48$non_lazy_ptr)
  "_ubrk_next_48", referenced from:
      _icuNext in libsqlite3-cerod.a(sqlite3_cerod.o)

Any idea what I'm doing wrong?

Edited to add:

When I add the libraries to the project (right-click on the project name, then Add Existing...), I get this:

ld: warning: in /Users/eric.grunin/dev/iOS/icu/source/lib/libicudata.a, file was built for unsupported file format which is not the architecture being linked (i386)
ld: warning: in /Users/eric.grunin/dev/iOS/icu/source/lib/libicui18n.a, file was built for unsupported file format which is not the architecture being linked (i386)
ld: warning: in /Users/eric.grunin/dev/iOS/icu/source/lib/libicuio.a, file was built for unsupported file format which is not the architecture being linked (i386)
ld: warning: in /Users/eric.grunin/dev/iOS/icu/source/lib/libicule.a, file was built for unsupported file format which is not the architecture being linked (i386)
ld: warning: in /Users/eric.grunin/dev/iOS/icu/source/lib/libiculx.a, file was built for unsupported file format which is not the architecture being linked (i386)
ld: warning: in /Users/eric.grunin/dev/iOS/icu/source/lib/libicutu.a, file was built for unsupported file format which is not the architecture being linked (i386)
ld: warning: in /Users/eric.grunin/dev/iOS/icu/source/lib/libicuuc.a, file was built for unsupported file format which is not the architecture being linked (i386)

That's why I think I'm building the library incorrectly. It's as if it's saying:

  • It can't tell what architecture the .a files are built for
  • libsqlite3-cerod.a is built for i386

I don't understand either possibility, but I'm new to iPhone development.

Edited to add

I tried @Sergio Moura's solution, and got the error mentioned in my comment.

I tried @sergio's solution, which built. But I'm still getting the equivalent errors, starting with:

ld: warning: in /Users/eric.grunin/dev/iOS/icu/iosbuild/lib/libicudata.a, file was built for unsupported file format which is not the architecture being linked (i386)

Might I be telling Xcode the wrong thing? I'm right-clicking on the project name, then selecting "Add->Existing File", and choosing the six or seven .a files from /icu/iosbuild/lib. Is that the correct process?

Note:

@sergio is recommending configure --host=arm-apple-darwin, @Sergio Moura is using configure --target=arm-apple-darwin. Neither made a difference, alas.

Edit #2

Targeting the device (instead of the emulator) solved all but one of the link errors! Here's what's left:

Undefined symbols for architecture armv6:
  "___sync_synchronize", referenced from:
      _ucol_initUCA_48 in libicui18n.a(ucol_res.ao)
      udata_getHashTable()      in libicuuc.a(udata.ao)
      _umtx_init_48 in libicuuc.a(umutex.ao)
      _initCache in libicuuc.a(uresbund.ao)
      icu_48::hasService()       in libicui18n.a(coll.ao)
      _ucol_initInverseUCA_48 in libicui18n.a(ucol_bld.ao)
      icu_48::locale_set_default_internal(char const*)in libicuuc.a(locid.ao)
      ...
ld: symbol(s) not found for architecture armv6

This was preceded by a cascade of these warnings:

ld: warning: CPU_SUBTYPE_ARM_ALL subtype is deprecated: /Users/eric.grunin/dev/iOS/icu/iosbuild/lib/libicuuc.a(resbund.ao)
ld: warning: CPU_SUBTYPE_ARM_ALL subtype is deprecated: /Users/eric.grunin/dev/iOS/icu/iosbuild/lib/libicuuc.a(ustrfmt.ao)

Edit #3

@Stephen R. Loomis's suggestion that I change #define U_HAVE_GCC_ATOMICS from 1 to 0 (in platform.h) made no difference, alas. I also realized that the last line of the error (not found for architecture arm6) didn't mean it would work for arm7, it was only an fyi that this was a cross-compile. When I specified an arm7 build, it failed with the same messages. Alas.

Edit #4

Success!

Summary: @sergio's build flags were essentially correct. I added -DU_HAVE_GCC_ATOMICS=0 to the ios build's CFLAGS. The one thing I had been doing wrong was not realizing I needed to cross-compile the library to create a device build.

I haven't tried to repeat this for the simulator, but that's outside the scope of my question.

Special thanks to Steven R. Loomis for pitching in, and to Sergio Moura for getting things rolling.

egrunin
  • 24,650
  • 8
  • 50
  • 93

5 Answers5

5

EDIT:

I can confirm that if you do, as Steven R. Loomis suggests:

  1. set U_HAVE_GCC_ATOMICS to 0 in icu/source/common/unicode/platform.h

  2. make distclean

  3. sh cross_configure.sh (using my script, i.e., if you are using it)

the problem should be solved. Indeed, without doing this, the built libraries contain the offending undefined symbol:

sergio@sfogliatella$ nm -a ./lib/libicuuc.a | grep __sync_
     U ___sync_synchronize
     U ___sync_val_compare_and_swap_4
     U ___sync_synchronize
     U ___sync_synchronize
     U ___sync_synchronize
     U ___sync_synchronize
     U ___sync_synchronize
     U ___sync_synchronize
     U ___sync_synchronize
     U ___sync_synchronize
     U ___sync_synchronize
     U ___sync_synchronize
     U ___sync_synchronize

After following the above suggestion, this is the result for the same command:

sergio@sfogliatella$ nm -a ./lib/libicuuc.a | grep __sync_
nm: no name list
nm: no name list

So, definitely, the offending symbol is not present in the binaries.

END EDIT.

Cross-compiling libicu for iOS requires two separate steps:

  1. compiling libicu for your host (MacOS) in a build directory;

  2. cross-compiling libicu for iOS by also specifying the cross-compile directory.

The reason why step 1 is necessary is that libicu will bootstrap itself a bit, i.e., it will compile some intermediate tools, which will be then used in the rest of the build process; those tools need to be ran on the host platform, so they are to be available.

Well, all in all, you can follow the steps (1. compile for the host):

$ cd $icu
$ mkdir hostbuild
$ cd hostbuild
$ ../icu/source/configure <configure settings you need>
$ gnumake

Once this is done, it's time to cross-compile (2. compile for iOS):

$ cd $icu  (or cd ../ from the previous directory)
$ mkdir iosbuild
$ cd iosbuild
$ sh ../cross_configure_icu.sh
$ gnumake

Where cross_configure_icu.sh is a shell script similar to those proposed by Sergio Moura above, but customized for libicu and using the more advanced llvm compiler:

DEVROOT=/Developer/Platforms/iPhoneOS.platform/Developer
SDKROOT=$DEVROOT/SDKs/iPhoneOS4.3.sdk
SYSROOT=$SDKROOT

ICU_PATH=<ABSOLUTE_PATH_TO_YOUR_ICU_DIR>
ICU_FLAGS="-I$ICU_PATH/source/common/ -I$ICU_MYSRC/source/tools/tzcode/ "

export CXXPP=
export CXXPPFLAGS=
export CPPFLAGS="-I$SDKROOT/usr/lib/gcc/arm-apple-darwin10/4.2.1/include/ -I$SDKROOT/usr/llvm-gcc-4.2/lib/gcc/arm-apple-darwin10/4.2.1/include/ -I$SDKROOT/usr/include/ -I$SDKROOT/usr/include/c++/4.2.1/armv7-apple-darwin10/ -I./include/ -miphoneos-version-min=2.2 $ICU_FLAGS"

export CFLAGS="$CPPFLAGS -pipe -no-cpp-precomp -isysroot $SDKROOT"
export CPP="$DEVROOT/usr/bin/cpp $CPPFLAGS"
export CXXFLAGS="$CFLAGS" 
export CC="$DEVROOT/usr/llvm-gcc-4.2/bin/arm-apple-darwin10-llvm-gcc-4.2"
export CXX="$DEVROOT/usr/llvm-gcc-4.2/bin/arm-apple-darwin10-llvm-g++-4.2"
export LDFLAGS="-L$SDKROOT/usr/lib/ -isysroot $SDKROOT -Wl,-dead_strip -miphoneos-version-min=2.0"

sh $ICU_PATH/source/configure --host=arm-apple-darwin --enable-static --disable-shared -with-cross-build=$ICU_PATH/hostbuild

In the above script (source), ICU_PATH is an absolute path because libicu configure so requires for the with-cross-build option. Again, check your values for the SDK and compilers, but this should be ok for 4.3.

Finally, you should take into account that Apple has (half) rejected at least one app that was linked against libicu, because it uses reserved APIs. Have a look at this S.O. topic.

EDIT:

happy the hear that you could compile!

now, to the linking problem.

first of all, please check that the libicu libraries are in the correct format:

sergio@sfogliatella$ lipo -info ./lib/libicuuc.a 

output should be (for any of the libs):

input file ./lib/libicuuc.a is not a fat file
Non-fat file: ./lib/libicuuc.a is architecture: arm

If this is fine, then next question: are you building for the simulator or for the device? simulator needs i386 libraries, device arm libraries... from the error message you show:

ld: warning: ... file was built for unsupported file format which is not the architecture being linked (i386)

it seems to me that you are building against the simulator... for that you will need "normal" macos x libs...

Community
  • 1
  • 1
sergio
  • 68,819
  • 11
  • 102
  • 123
  • Thanks, I'll try this. I did see that other comment, it's a bit of a worry but I don't have much choice here. – egrunin Nov 17 '11 at 19:18
  • @egrunin - what kind of worry? You have to build ICU once for your platform so that it can run its own tools, and then once targetting your platform. That's how it is designed to work. —Steven, ICU project. – Steven R. Loomis Nov 17 '11 at 20:18
  • @Steven R. Loomis: see the last paragraph in my answer... the worry about Apple rejecting libicu... :-) – sergio Nov 17 '11 at 20:20
  • Clever workaround for missing tzfile.h - including the version that comes with ICU **for purposes of building its time zone compiler**. However, it's not guaranteed at all to be relevant to your platform. – Steven R. Loomis Nov 17 '11 at 20:33
  • Thanks for the follow-up, I'll try those steps tonight. In the normal course of development I do have to support both targets, but if I can get *either* to build that's enough for now. – egrunin Nov 17 '11 at 23:25
  • 1
    @sergio iOS itself is built on top of ICU, so that's probably where the rejection would come in, if you call through to the ICU on iOS. Note, we don't usually call it libicu but just ICU. Apple builds it into one library but that is not the default behavior across platforms. – Steven R. Loomis Nov 17 '11 at 23:29
  • @Steven R. Loomis: I think that Apple is using a tool to see what library calls an app makes, and they got a false positive on ICU calls built into SQLite. (They don't call the OS copies of ICU functions, they call instances from an ICU build installed with the app.) – egrunin Nov 18 '11 at 06:32
  • @egrunin I wonder if the --with-library-suffix option to ICU configure would work. (you would only need to do it on the arm version of ICU). --with-library-suffix=egrunin would make your functions look something like "uregex_open_48_egrunin" - personalized. – Steven R. Loomis Nov 18 '11 at 14:45
  • I added -DU_HAVE_GCC_ATOMICS=0 to the iosbuild CFLAGS, and that eliminated the problem. – egrunin Nov 21 '11 at 20:11
  • Is there an update on whether Apple will approve an app with SQLite+ICU libs linked into the app? – tofutim Feb 02 '12 at 13:45
  • Having spent a while trying to get this to work on iOS5.1 / Xcode4.3 (and not understanding what most of these things do), I finally found that a path needs to be updated for the CPP directive, to `export CPP="$DEVROOT/usr/llvm-gcc-4.2/bin/llvm-cpp-4.2 $CPPFLAGS"`. Thanks for all the information. – Rupert May 10 '12 at 13:08
  • I finally got this to compile on iOS 6 by changing the DEVROOT to /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer and SDKROOT to $DEVROOT/SDKs/iPhoneOS6.0.sdk. And also CPP="$DEVROOT/usr/bin/llvm-cpp-4.2 $CPPFLAGS" and also -I$ICU_MYSRC is incorrect. It should be $ICU_PATH – Tap Forms Oct 09 '12 at 23:35
  • The end result is a bunch of armv7 static libraries which will increase the size of my app by about 20 megabytes! And now for something worse... Is there a way to compile it for armv7s for the new iPhone 5? When I add -arch armv7 armv7s to the CFLAGS, I get a configure error: C compiler cannot create executables – Tap Forms Oct 09 '12 at 23:37
  • @TapForms see what config.log says about the configure error. Use the data customizer http://apps.icu-project.org/datacustom to adjust the data file size if you don't need *ALL* of the data. static link should not add that much worth of real code. – Steven R. Loomis Nov 11 '12 at 01:09
  • Is there a way to build the ICU package as a dylib instead of static? – KerrM Jul 11 '22 at 17:09
2

I used iOS SDK version 6.1, with clang and building against the c++11 standard library. I found that setting environment variables such as CXXFLAGS had no affect, and trying to pass them to 'configure' on the command line seemed to break it entirely. I ended up making a clang, clang++, and ld scripts that would allow me to pass in additional parameters. For example, my clang script:

#This script circumvents gnumake getting rid of our flags. Use the environment variable $MORE_CFLAGS
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang "$@" $MORE_CFLAGS

The others are identical, but substitute clang++ and ld where appropriate, and use MORE_CXXFLAGS and MORE_LDFLAGS respectively.

Lastly, I made this script, which does a host build, a simulator build, and an iOS build. Note that the simulator build includes debug info, and the iOS version is -O2 optimized. It then lipos the libs (makes a universal binary) and copies them, along with the include folder, to a target specified by INSTALL_PATH. Lines 3-5 are used to configure the script. Place all 4 of these scripts in the same folder and execute this last one from the command line:

#unpack the ICU source and point $ICU_PATH at it

ICU_PATH="$HOME/Downloads/icu"
ICU_FLAGS="-I$ICU_PATH/source/common/ -I$ICU_PATH/source/tools/tzcode/ "
INSTALL_PATH="$HOME/Documents/git/gamelib/Graphics/Text/icu/51.1"
SDKROOT=`xcrun --sdk iphoneos --show-sdk-path`
SIMULATOR_SDKROOT=`xcrun --sdk iphonesimulator --show-sdk-path`


SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
SAVEPATH=$PATH

cd $ICU_PATH
mkdir host_build
cd host_build
../source/configure
gnumake

PATH=$SCRIPT_DIR:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:$SAVEPATH
cd $ICU_PATH
mkdir iPhoneSimulator_build
cd iPhoneSimulator_build
#PATH points to the folder that contains this script, which should also contain scripts titled clang, clang++, and ld
#those scripts call the actual clang, clang++, and ld, appending MORE_CFLAGS, MORE_CXXFLAGS, and MORE_LDFLAGS respectively
export MORE_CFLAGS="-arch i386 -pipe -std=c99 -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=5.0 -isysroot $SIMULATOR_SDKROOT $ICU_FLAGS"
export MORE_CXXFLAGS="-arch i386 -pipe -std=c++11 -stdlib=libc++ -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=5.0 -isysroot $SIMULATOR_SDKROOT $ICU_FLAGS"
export MORE_LDFLAGS="-arch i386 -isysroot $SIMULATOR_SDKROOT -miphoneos-version-min=5.0"
$ICU_PATH/source/configure --enable-debug --disable-release --with-cross-build="$ICU_PATH/host_build" --prefix="$ICU_PATH/iPhoneSimulator_build/install" --enable-static=yes --enable-shared=no
gnumake clean
gnumake VERBOSE=1 install

PATH=$SCRIPT_DIR:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:$SAVEPATH
cd $ICU_PATH
mkdir iPhoneOS_build
cd iPhoneOS_build
#PATH points to the folder that contains this script, which should also contain scripts titled clang, clang++, and ld
#those scripts call the actual clang, clang++, and ld, appending MORE_CFLAGS, MORE_CXXFLAGS, and MORE_LDFLAGS respectively
export MORE_CFLAGS="-arch armv7 -pipe -std=c99 -O2 -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=5.0 -isysroot $SDKROOT $ICU_FLAGS"
export MORE_CXXFLAGS="-arch armv7 -pipe -std=c++11 -stdlib=libc++ -O2 -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=5.0 -isysroot $SDKROOT $ICU_FLAGS"
export MORE_LDFLAGS="-arch armv7 -isysroot $SDKROOT -miphoneos-version-min=5.0"
$ICU_PATH/source/configure --host=arm-apple-darwin --with-cross-build="$ICU_PATH/host_build" --prefix="$ICU_PATH/iPhoneOS_build/install" --enable-static=yes --enable-shared=no
gnumake clean
gnumake VERBOSE=1 install

PATH=$SAVEPATH

mkdir "$INSTALL_PATH/lib"
for file in $ICU_PATH/iPhoneOS_build/install/lib/*.a; do
    BASENAME="${file##*/}"
    lipo "$ICU_PATH/iPhoneOS_build/install/lib/$BASENAME" "$ICU_PATH/iPhoneSimulator_build/install/lib/$BASENAME" -create -output "$INSTALL_PATH/lib/$BASENAME"
done

rm -r "$INSTALL_PATH/include"
cp -r "$ICU_PATH/iPhoneOS_build/install/include" "$INSTALL_PATH/include"
Shawn Blakesley
  • 1,743
  • 1
  • 17
  • 33
Brent
  • 4,153
  • 4
  • 30
  • 63
  • What version of the ICU library are you building? The accepted answer works with 49, doesn't work with 51. – egrunin May 02 '13 at 19:17
2

I have the simple solution for all of this ugliness now.

https://github.com/dbquarrel/icu4c-xcframework

Download this makefile, it will get ICU, and build an ICU.xcframework for (M1/ARM/x86) for (macOS, macCatalyst, iOS, iOS simulator).

One shot and all headaches gone.

Long time later to answer the question but probably couldn't have been done like this so long ago.

dbquarrel
  • 1,446
  • 1
  • 10
  • 8
1

If you have the source, do you really need to link the library? Just add the sources to your XCode project and you should be good to go...

If you really want to build a library, I'd suggest you to create an XCode project for the library with the iPhone as your target, and link that library to your code, as your library is built to run in your MacOS computer (according to your error logs).

EDIT

To build it from the command line and assuming you're not using iOS 5 (because of your version of XCode), I've borrowed and adapted this set of instructions to properly setup the flags to configure and build correctly the binaries to your platform from here:

export IOS_BASE_SDK=4.2
export IOS_DEPLOY_TGT=4.2
export DEVROOT=/Developer/Platforms/iPhoneOS.platform/Developer
export SDKROOT=$DEVROOT/SDKs/iPhoneOS$IOS_BASE_SDK.sdk
export CFLAGS="-arch armv7 -pipe -no-cpp-precomp -isysroot $SDKROOT -miphoneos-version-min=$IOS_DEPLOY_TGT -I$SDKROOT/usr/include/"

export CPP=$DEVROOT/usr/bin/cpp-4.2
export CXX=$DEVROOT/usr/bin/g++-4.2
export CXXCPP=$DEVROOT/usr/bin/cpp-4.2
export CC=$DEVROOT/usr/bin/gcc-4.2
export LD=$DEVROOT/usr/bin/ld
export AR=$DEVROOT/usr/bin/ar
export AS=$DEVROOT/usr/bin/as
export NM=$DEVROOT/usr/bin/nm
export RANLIB=$DEVROOT/usr/bin/ranlib
export LDFLAGS="-L$SDKROOT/usr/lib/"

export CPPFLAGS=$CFLAGS
export CXXFLAGS=$CFLAGS

./configure --target=arm-apple-darwin --enable-static --disable-shared

Please, properly set the IOS version on the first two instructions to the correct value of your environment.

If you're going to use iOS 5 SDK, you'll need to change the name of the compiler binaries since they've changed.

Sergio Moura
  • 4,888
  • 1
  • 21
  • 38
  • Thanks, I'll try this now. And yes, I'm using the 4.3 SDK. For the last hour I've been trying your other suggestion, and it's been very difficult - there's no easy way to tell what source belongs in the lib and what doesn't. – egrunin Nov 17 '11 at 18:11
  • Tried your script, results appended to my original post. – egrunin Nov 17 '11 at 18:33
  • 1
    Sorry I can't test any further. Maybe because I have iOS 5 installed on my Mac, mine didn't retrieved any errors, but maybe you could try the config command line provided on the readme (http://icu-project.org/repos/icu/icu/trunk/readme.html#HowToCrossCompileICU) like this: `sh /icu/source/configure --host=arm-apple-darwin --with-cross-build=/buildA --enable-static --disable-shared`? – Sergio Moura Nov 17 '11 at 18:38
  • 1
    Sergio - you beat me to it by 5 minutes. That's exactly what they should do (--host, --with-cross-build..). Steven, ICU project. – Steven R. Loomis Nov 17 '11 at 18:50
  • Woot! Glad I'm in the right direction, then, since I don't know anything about ICU. =) I was just introduced to it by this question (and now reading what it's capable of) – Sergio Moura Nov 17 '11 at 18:52
  • First pass fine, second pass not: `icu/source/common/putil.c:661:20: error: tzfile.h: No such file or directory` - going to try the other @sergio now... – egrunin Nov 17 '11 at 19:49
  • @SergioMoura hope you enjoy ICU! – Steven R. Loomis Nov 17 '11 at 20:22
  • @egrunin tzfile.h must have disappeared… see http://lists.macosforge.org/pipermail/macports-users/2011-January/023298.html for a thread that might be of interest. I don't think they contributed the patch upstream to ICU nor filed a ticket. – Steven R. Loomis Nov 17 '11 at 20:28
  • This doesn't work with the iOS 6 SDK and Xcode installed in /Applications. I've been fiddling around with all the parameters above, but no luck so far. Does anyone have a solution for iOS 6 SDK? – Tap Forms Oct 09 '12 at 22:26
1

re: sync synchronize: someone may be lying about the atomics or there's some gcc library needed. try #define U_HAVE_GCC_ATOMICS 0 at the top of icu/source/common/unicode/uconfig.h ( note: ARM seems to have a weak memory model, so this change will result in more locking/unlocking than would otherwise be necessary, but still safe. )

Steven R. Loomis
  • 4,228
  • 28
  • 39
  • That threw errors, I think you meant /source/common/unicode/ **platform.h**. – egrunin Nov 18 '11 at 21:24
  • Doesn't matter where. We're not going to generate platform.h in 49 and later versions, but it gets overwritten by configure. So it's usually not a good place to put #defines. – Steven R. Loomis Nov 18 '11 at 21:29
  • Not sure if I've done it wrong then - my platform.h didn't get overwritten. – egrunin Nov 18 '11 at 22:31
  • If you are on ICU before version 49, it does get overwritten when 'configure' runs. In version 49 (not yet released), no .h files are dynamically generated (hooray!). – Steven R. Loomis Nov 19 '11 at 00:23