summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
Diffstat (limited to 'content')
-rw-r--r--content/browser/mac/closure_blocks_leopard_compat.S139
-rw-r--r--content/browser/mac/closure_blocks_leopard_compat.h104
-rw-r--r--content/browser/mac/closure_blocks_leopard_compat_unittest.cc98
-rw-r--r--content/content.gyp62
-rw-r--r--content/content_tests.gypi6
5 files changed, 409 insertions, 0 deletions
diff --git a/content/browser/mac/closure_blocks_leopard_compat.S b/content/browser/mac/closure_blocks_leopard_compat.S
new file mode 100644
index 0000000..88a63da
--- /dev/null
+++ b/content/browser/mac/closure_blocks_leopard_compat.S
@@ -0,0 +1,139 @@
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Definitions of symbols that may be needed at runtime but aren't necessarily
+# present in the SDK chosen for compilation.
+#
+# This file provides symbols for _NSConcreteGlobalBlock and
+# _NSConcreteStackBlock, normally present in libSystem.dylib and provided by
+# by libclosure-38/data.c in Mac OS X 10.6 and later. It also provides symbols
+# for various block runtime functions provided by libclosure-38/runtime.c.
+# When using the 10.5 SDK, the symbols are not present. This file's definition
+# can be used with extreme care in an application that needs to use the 10.5
+# SDK in conjunction with blocks.
+#
+# This file cooperates with the build system to produce a dynamic library
+# that, when linked against, causes dependents to look in libSystem for the
+# symbols provided here. It also cooperates with a header that causes
+# dependents to treat the symbols provided here as weak imports, critical for
+# the resultant output to be loadable on 10.5.
+
+# To simplify things, this file assumes it's being built with the 10.5 SDK,
+# a deployment target of 10.5, and is producing 32-bit x86 code. Other
+# combinations are possible, but not interesting for the time being. See
+# <sys/cdefs.h> for interesting ways that names might be mangled in other
+# configurations.
+
+#include <AvailabilityMacros.h>
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED != MAC_OS_X_VERSION_10_5 || \
+ MAC_OS_X_VERSION_MAX_ALLOWED != MAC_OS_X_VERSION_10_5 || \
+ !defined(__i386__)
+#error This file only supports 32-bit x86 code with both SDK and DT set to 10.5
+#endif
+
+#define DEFINE_GLOBAL_SYMBOL(name) \
+ .globl name ## ;\
+ name ## :
+
+.text
+
+# Mac OS X 10.6.8 libclosure-38/runtime.c
+
+DEFINE_GLOBAL_SYMBOL(__Block_copy)
+DEFINE_GLOBAL_SYMBOL(__Block_release)
+DEFINE_GLOBAL_SYMBOL(__Block_object_assign)
+DEFINE_GLOBAL_SYMBOL(__Block_object_dispose)
+
+.section __DATA,__data
+
+# Mac OS X 10.6.8 libclosure-38/data.c
+
+DEFINE_GLOBAL_SYMBOL(__NSConcreteGlobalBlock)
+DEFINE_GLOBAL_SYMBOL(__NSConcreteStackBlock)
+
+# When this file is in use, the linker is expected to link things against both
+# this file and the real copy of libSystem present in the SDK. When doing so,
+# the linker is smart enough to produce only one LC_LOAD_DYLIB load command.
+# However, it's not smart enough to notice that while this file's dylib only
+# provides weak-imported symbols, the real libSystem's dylib does not.
+# Consequently, it may produce an LC_LOAD_WEAK_DYLIB load command for
+# libSystem instead of an ordinary LC_LOAD_DYLIB command. LC_LOAD_WEAK_DYLIB
+# declares that any symbol offered by the library, and in fact the entire
+# library, is permitted to be missing at runtime. This is entirely
+# inappropriate for libSystem. To counteract this problem, this file also
+# defines some other symbols that libSystem provides. Dependents of this
+# library are not expected to treat these other symbols as weak imports. In
+# order for any dependent that links against this library to load it with an
+# LC_LOAD_DYLIB command instead of an LC_LOAD_WEAK_DYLIB command, this library
+# must satisfy at least one unresolved non-weak-import symbol required by the
+# dependent.
+
+.text
+
+# |exit| is a good one: because it's referenced by crt1.o, ordinary executables
+# are guaranteed to need this symbol. Unfortunately, there's no such symbol in
+# dylib1.o that libSystem is expected to provide, so a few other common libc
+# symbols are thrown into the mix.
+DEFINE_GLOBAL_SYMBOL(_exit)
+
+# Include |close| because well-written programs that use the standard library
+# are likely to refer to it. Include |open| for good measure because it goes
+# pretty well with this. Include the stdio abstractions for these functions
+# as well.
+DEFINE_GLOBAL_SYMBOL(_close$UNIX2003)
+DEFINE_GLOBAL_SYMBOL(_open$UNIX2003)
+DEFINE_GLOBAL_SYMBOL(_fclose)
+DEFINE_GLOBAL_SYMBOL(_fopen)
+DEFINE_GLOBAL_SYMBOL(_fdopen)
+DEFINE_GLOBAL_SYMBOL(_freopen$UNIX2003)
+
+# Commonly-used allocation functions.
+DEFINE_GLOBAL_SYMBOL(_malloc)
+DEFINE_GLOBAL_SYMBOL(_calloc)
+DEFINE_GLOBAL_SYMBOL(_realloc)
+DEFINE_GLOBAL_SYMBOL(_reallocf)
+DEFINE_GLOBAL_SYMBOL(_valloc)
+DEFINE_GLOBAL_SYMBOL(_free)
+
+# Include |printf|, |fprintf|, |sprintf|, |snprintf|, and |puts|, because
+# small test programs are likely to refer to one of these. puts is rarely
+# invoked directly, but the compiler may optimize simple printf calls into
+# puts calls.
+DEFINE_GLOBAL_SYMBOL(_printf)
+DEFINE_GLOBAL_SYMBOL(_fprintf)
+DEFINE_GLOBAL_SYMBOL(_sprintf)
+DEFINE_GLOBAL_SYMBOL(_snprintf)
+DEFINE_GLOBAL_SYMBOL(_puts)
+
+# Some <string.h> functions that are commonly used.
+DEFINE_GLOBAL_SYMBOL(_memcmp)
+DEFINE_GLOBAL_SYMBOL(_memcpy)
+DEFINE_GLOBAL_SYMBOL(_memmove)
+DEFINE_GLOBAL_SYMBOL(_memset)
+DEFINE_GLOBAL_SYMBOL(_strcasecmp)
+DEFINE_GLOBAL_SYMBOL(_strcat)
+DEFINE_GLOBAL_SYMBOL(_strchr)
+DEFINE_GLOBAL_SYMBOL(_strcmp)
+DEFINE_GLOBAL_SYMBOL(_strcpy)
+DEFINE_GLOBAL_SYMBOL(_strdup)
+DEFINE_GLOBAL_SYMBOL(_strlcat)
+DEFINE_GLOBAL_SYMBOL(_strlcpy)
+DEFINE_GLOBAL_SYMBOL(_strlen)
+DEFINE_GLOBAL_SYMBOL(_strncasecmp)
+DEFINE_GLOBAL_SYMBOL(_strncat)
+DEFINE_GLOBAL_SYMBOL(_strncmp)
+DEFINE_GLOBAL_SYMBOL(_strncpy)
+DEFINE_GLOBAL_SYMBOL(_strnstr)
+DEFINE_GLOBAL_SYMBOL(_strstr)
+
+# Some data-section symbols that might be referenced.
+
+.section __DATA,__data
+
+DEFINE_GLOBAL_SYMBOL(___stdinp)
+DEFINE_GLOBAL_SYMBOL(___stdoutp)
+DEFINE_GLOBAL_SYMBOL(___stderrp)
+
+#undef DEFINE_GLOBAL_SYMBOL
diff --git a/content/browser/mac/closure_blocks_leopard_compat.h b/content/browser/mac/closure_blocks_leopard_compat.h
new file mode 100644
index 0000000..518c7b1
--- /dev/null
+++ b/content/browser/mac/closure_blocks_leopard_compat.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MAC_CLOSURE_BLOCKS_LEOPARD_COMPAT_H_
+#define CONTENT_BROWSER_MAC_CLOSURE_BLOCKS_LEOPARD_COMPAT_H_
+#pragma once
+
+// libclosure (blocks) compatibility for Mac OS X 10.5 (Leopard)
+//
+// Background material:
+// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Blocks
+// http://opensource.apple.com/source/libclosure/libclosure-38/
+//
+// Leopard doesn't support blocks. Chrome supports Leopard. Chrome needs to use
+// blocks.
+//
+// In any file where you use blocks (any time you type ^{...}), you must
+// #include this file to ensure that the runtime symbols referenced by code
+// emitted by the compiler are marked for weak-import. This means that if
+// these symbols are not present at runtime, the program will still load, but
+// their values will be NULL.
+//
+// In any target (in the GYP sense) where you use blocks, you must also depend
+// on the closure_blocks_leopard_compat target to ensure that these symbols
+// will be available at link time, even when the 10.5 SDK is in use. This
+// allows the continued use of the 10.5 SDK, which does not contain these
+// symbols.
+//
+// This does not relieve you of the responsibility to not use blocks on
+// Leopard. Because runtime support for Blocks still isn't present on that
+// operating system, the weak-imported symbols will have value 0 and attempts
+// to do anything meaningful with them will fail or crash. You must take care
+// not to enter any codepath that uses blocks on Leopard. The base::mac::IsOS*
+// family may be helpful.
+//
+// Although this scheme allows the use of the 10.5 SDK and 10.5 runtime in an
+// application that uses blocks, it is still necessary to use a compiler that
+// supports blocks. GCC 4.2 as shipped with Xcode 3.2 for Mac OS X 10.6
+// qualifies, as do sufficiently recent versions of clang. GCC 4.2 as shipped
+// with Xcode 3.1 for Mac OS X 10.5 does not qualify.
+
+// _NSConcreteGlobalBlock and _NSConcreteStackBlock are private implementation
+// details of libclosure defined in libclosure/libclosure-38/Block_private.h,
+// but they're exposed from libSystem as public symbols, and the block-enabled
+// compiler will emit code that references these symbols. Because the symbols
+// aren't present in 10.5's libSystem, they must be declared as weak imports
+// in any file that uses blocks. Any block-using file must #include this
+// header to guarantee that the symbols will show up in linked output as weak
+// imports when compiling for a 10.5 deployment target. Because the symbols
+// are always present in 10.6 and higher, they do not need to be a weak
+// imports when the deployment target is at least 10.6.
+//
+// Both GCC and clang emit references to these symbols, providing implicit
+// declarations as needed, but respecting any user declaration when present.
+// See gcc-5666.3/gcc/c-parser.c build_block_struct_initlist,
+// gcc-5666.3/gcc/cp/parser.c build_block_struct_initlist, and
+// clang-2.9/lib/CodeGen/CodeGenModule.cpp
+// CodeGenModule::getNSConcreteGlobalBlock() and
+// CodeGenModule::getNSConcreteStackBlock().
+
+#include <AvailabilityMacros.h>
+
+#if defined(MAC_OS_X_VERSION_10_6) && \
+ MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 // SDK >= 10.6
+// Get the system's own declarations of these things if using an SDK where
+// they are present.
+#include <Block.h>
+#endif // SDK >= 10.6
+
+extern "C" {
+
+#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_5 // DT <= 10.5
+#define MAYBE_WEAK_IMPORT __attribute__((weak_import))
+#else // DT > 10.5
+#define MAYBE_WEAK_IMPORT
+#endif // DT <= 10.5
+
+MAYBE_WEAK_IMPORT extern void* _Block_copy(const void*);
+MAYBE_WEAK_IMPORT extern void _Block_release(const void*);
+MAYBE_WEAK_IMPORT extern void _Block_object_assign(void*,
+ const void*,
+ const int);
+MAYBE_WEAK_IMPORT extern void _Block_object_dispose(const void*, const int);
+
+MAYBE_WEAK_IMPORT extern void* _NSConcreteGlobalBlock[32];
+MAYBE_WEAK_IMPORT extern void* _NSConcreteStackBlock[32];
+
+#undef MAYBE_WEAK_IMPORT
+
+} // extern "C"
+
+// Macros from <Block.h>, in case <Block.h> is not present.
+
+#ifndef Block_copy
+#define Block_copy(...) \
+ ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__)))
+#endif
+
+#ifndef Block_release
+#define Block_release(...) _Block_release((const void *)(__VA_ARGS__))
+#endif
+
+#endif // CONTENT_BROWSER_MAC_CLOSURE_BLOCKS_LEOPARD_COMPAT_H_
diff --git a/content/browser/mac/closure_blocks_leopard_compat_unittest.cc b/content/browser/mac/closure_blocks_leopard_compat_unittest.cc
new file mode 100644
index 0000000..fd2e467
--- /dev/null
+++ b/content/browser/mac/closure_blocks_leopard_compat_unittest.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "base/mac/mac_util.h"
+#include "content/browser/mac/closure_blocks_leopard_compat.h"
+
+// Used in ClosureBlocksLeopardCompatTest.Global. Putting a block at global
+// scope results in a block structure whose isa field is set to
+// NSConcreteGlobalBlock, ensuring that symbol is referenced. This test needs
+// to be able to load on 10.5 where that symbol is not present at runtime, so
+// the real test here is that the symbol is weakly imported. If not, the
+// executable will fail to load.
+void (^global_block)(bool*) = ^(bool* ran_pointer) { *ran_pointer = true; };
+
+namespace {
+
+// It should be possible to declare a block on OSes as early as Leopard
+// (10.5). This should be buildable with the 10.5 SDK and a 10.5 deployment
+// target, and runnable on 10.5. However, the block itself is not expected to
+// be runnable on 10.5. This test verfies that blocks are buildable on 10.5
+// and runnable on Snow Leopard (10.6) and later.
+
+TEST(ClosureBlocksLeopardCompatTest, Stack) {
+ bool ran = false;
+
+ // This should result in a block structure whose isa field is set to
+ // NSConcreteStackBlock, ensuring that symbol is referenced. This test
+ // needs to be able to load on 10.5 where that symbol is not present at
+ // runtime, so the real test here checks that the symbol is weakly imported.
+ // If not, the executable will fail to load.
+
+ void (^test_block)(bool*) = ^(bool* ran_pointer) { *ran_pointer = true; };
+
+ ASSERT_FALSE(ran);
+
+ if (base::mac::IsOSSnowLeopardOrLater()) {
+ test_block(&ran);
+
+ EXPECT_TRUE(ran);
+ }
+}
+
+TEST(ClosureBlocksLeopardCompatTest, Global) {
+ bool ran = false;
+
+ ASSERT_FALSE(ran);
+
+ if (base::mac::IsOSSnowLeopardOrLater()) {
+ global_block(&ran);
+
+ EXPECT_TRUE(ran);
+ }
+}
+
+TEST(ClosureBlocksLeopardCompatTest, CopyRelease) {
+ if (base::mac::IsOSSnowLeopardOrLater()) {
+ // Protect the entire test in this conditional, because __block won't run
+ // on 10.5.
+ __block int value = 0;
+
+ typedef int (^TestBlockType)();
+ TestBlockType local_block = ^(void) { return ++value; };
+
+ ASSERT_EQ(0, value);
+
+ int rv = local_block();
+ EXPECT_EQ(1, rv);
+ EXPECT_EQ(rv, value);
+
+ // Using Block_copy, Block_release, and these other operations ensures
+ // that _Block_copy, _Block_release, _Block_object_assign, and
+ // _Block_object_dispose are referenced. This test needs to be able to
+ // load on 10.5 where these symbols are not present at runtime, so the
+ // real test here is that the symbol is weakly imported. If not, the
+ // executable will fail to load.
+
+ TestBlockType copied_block = Block_copy(local_block);
+
+ rv = copied_block();
+ EXPECT_EQ(2, rv);
+ EXPECT_EQ(rv, value);
+
+ rv = copied_block();
+ EXPECT_EQ(3, rv);
+ EXPECT_EQ(rv, value);
+
+ Block_release(copied_block);
+
+ rv = local_block();
+ EXPECT_EQ(4, rv);
+ EXPECT_EQ(rv, value);
+ }
+}
+
+} // namespace
diff --git a/content/content.gyp b/content/content.gyp
index 20b8581..cdc8712 100644
--- a/content/content.gyp
+++ b/content/content.gyp
@@ -117,6 +117,68 @@
],
},
],
+ 'conditions': [
+ ['OS=="mac"', {
+ 'targets': [
+ {
+ 'target_name': 'closure_blocks_leopard_compat',
+ 'conditions': [
+ ['mac_sdk == "10.5"', {
+ 'type': 'shared_library',
+ 'product_name': 'closure_blocks_leopard_compat_stub',
+ 'variables': {
+ # This target controls stripping directly. See below.
+ 'mac_strip': 0,
+ },
+ 'sources': [
+ 'browser/mac/closure_blocks_leopard_compat.S',
+ ],
+ 'xcode_settings': {
+ # These values are taken from libSystem.dylib in the 10.5
+ # SDK. Setting LD_DYLIB_INSTALL_NAME causes anything linked
+ # against this stub library to look for the symbols it
+ # provides in the real libSystem at runtime. When using ld
+ # from Xcode 4 or later (ld64-123.2 and up), giving two
+ # libraries with the same "install name" to the linker will
+ # cause it to print "ld: warning: dylibs with same install
+ # name". This is harmless, and ld will behave as intended
+ # here.
+ #
+ # The real library's compatibility version is used, and the
+ # value of the current version from the SDK is used to make
+ # it appear as though anything linked against this stub was
+ # linked against the real thing.
+ 'LD_DYLIB_INSTALL_NAME': '/usr/lib/libSystem.B.dylib',
+ 'DYLIB_COMPATIBILITY_VERSION': '1.0.0',
+ 'DYLIB_CURRENT_VERSION': '111.1.4',
+
+ # Turn on stripping (yes, even in debug mode), and add the -c
+ # flag. This is what produces a stub library (MH_DYLIB_STUB)
+ # as opposed to a dylib (MH_DYLIB). MH_DYLIB_STUB files
+ # contain symbol tables and everything else needed for
+ # linking, but are stripped of section contents. This is the
+ # same way that the stub libraries in Mac OS X SDKs are
+ # created. dyld will refuse to load a stub library, so this
+ # provides some insurance in case anyone tries to load the
+ # stub at runtime.
+ 'DEPLOYMENT_POSTPROCESSING': 'YES',
+ 'STRIP_STYLE': 'non-global',
+ 'STRIPFLAGS': '-c',
+ },
+ }, { # else: mac_sdk != "10.5"
+ # When using the 10.6 SDK or newer, the necessary definitions
+ # are already present in libSystem.dylib. There is no need to
+ # build a stub dylib to provide these symbols at link time.
+ # This target is still useful to cause those symbols to be
+ # treated as weak imports in dependents, who still must
+ # #include closure_blocks_leopard_compat.h to get weak imports.
+ 'type': 'none',
+ }],
+ ],
+ },
+ ],
+ }],
+ ],
},
{ # component != static_library
'target_defaults': {
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index fd79b78..5146d05 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -117,6 +117,7 @@
'browser/gpu/gpu_blacklist_unittest.cc',
'browser/in_process_webkit/webkit_context_unittest.cc',
'browser/in_process_webkit/webkit_thread_unittest.cc',
+ 'browser/mac/closure_blocks_leopard_compat_unittest.cc',
'browser/mach_broker_mac_unittest.cc',
'browser/renderer_host/gtk_key_bindings_handler_unittest.cc',
'browser/renderer_host/media/audio_input_device_manager_unittest.cc',
@@ -181,6 +182,11 @@
['exclude', '^browser/renderer_host/gtk_key_bindings_handler_unittest.cc'],
],
}],
+ ['OS=="mac"', {
+ 'dependencies': [
+ 'closure_blocks_leopard_compat',
+ ],
+ }],
],
},
],