Commit 1aa65000 authored by Thomas Van Lenten's avatar Thomas Van Lenten

Update the ObjC version checks to support a min and current version.

- Capture the version used to generated.
- Check at compile time and runtime that generated code isn't from a newer
  version, also check that the min version required is also supported.
- Keep the old constants/macros/functions to special case the last version
  that was working so those generated sources still work until we decide
  otherwise.
parent 86fcd879
#!/bin/bash
#!/bin/bash -eu
# This script checks that the runtime version number constant in the compiler
# source and in the runtime source is the same.
......@@ -8,8 +8,6 @@
# builds would break. At the same time, we don't want the runtime source
# depending on the compiler sources; so two copies of the constant are needed.
set -eu
readonly ScriptDir=$(dirname "$(echo $0 | sed -e "s,^\([^/]\),$(pwd)/\1,")")
readonly ProtoRootDir="${ScriptDir}/../.."
......@@ -18,39 +16,40 @@ die() {
exit 1
}
readonly ConstantName=GOOGLE_PROTOBUF_OBJC_GEN_VERSION
# Collect version from plugin sources.
readonly PluginSrc="${ProtoRootDir}/src/google/protobuf/compiler/objectivec/objectivec_file.cc"
readonly PluginVersion=$( \
cat "${PluginSrc}" \
| sed -n -e "s:const int32 ${ConstantName} = \([0-9]*\);:\1:p"
)
if [[ -z "${PluginVersion}" ]] ; then
die "Failed to find ${ConstantName} in the plugin source (${PluginSrc})."
fi
# Collect version from runtime sources.
readonly GeneratorSrc="${ProtoRootDir}/src/google/protobuf/compiler/objectivec/objectivec_file.cc"
readonly RuntimeSrc="${ProtoRootDir}/objectivec/GPBBootstrap.h"
readonly RuntimeVersion=$( \
cat "${RuntimeSrc}" \
| sed -n -e "s:#define ${ConstantName} \([0-9]*\):\1:p"
)
if [[ -z "${RuntimeVersion}" ]] ; then
die "Failed to find ${ConstantName} in the runtime source (${RuntimeSrc})."
fi
# Compare them.
if [[ "${PluginVersion}" != "${RuntimeVersion}" ]] ; then
die "Versions don't match!
Plugin: ${PluginVersion} from ${PluginSrc}
Runtime: ${RuntimeVersion} from ${RuntimeSrc}
check_constant() {
local ConstantName="$1"
# Collect version from generator sources.
local GeneratorVersion=$( \
cat "${GeneratorSrc}" \
| sed -n -e "s:const int32 ${ConstantName} = \([0-9]*\);:\1:p"
)
if [[ -z "${GeneratorVersion}" ]] ; then
die "Failed to find ${ConstantName} in the generator source (${GeneratorSrc})."
fi
# Collect version from runtime sources.
local RuntimeVersion=$( \
cat "${RuntimeSrc}" \
| sed -n -e "s:#define ${ConstantName} \([0-9]*\):\1:p"
)
if [[ -z "${RuntimeVersion}" ]] ; then
die "Failed to find ${ConstantName} in the runtime source (${RuntimeSrc})."
fi
# Compare them.
if [[ "${GeneratorVersion}" != "${RuntimeVersion}" ]] ; then
die "${ConstantName} values don't match!
Generator: ${GeneratorVersion} from ${GeneratorSrc}
Runtime: ${RuntimeVersion} from ${RuntimeSrc}
"
fi
fi
}
# Do the check.
check_constant GOOGLE_PROTOBUF_OBJC_VERSION
# Success
......@@ -93,10 +93,27 @@
// Meant to be used internally by generated code.
#define GPB_METHOD_FAMILY_NONE __attribute__((objc_method_family(none)))
// The protoc-gen-objc version which works with the current version of the
// generated Objective C sources. In general we don't want to change the
// runtime interfaces (or this version) as it means everything has to be
// regenerated.
// ----------------------------------------------------------------------------
// These version numbers are all internal to the ObjC Protobuf runtime; they
// are used to ensure compatibility between the generated sources and the
// headers being compiled against and/or the version of sources being run
// against.
//
// Meant to be used internally by generated code.
#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30002
// They are all #defines so the values are captured into every .o file they
// are used in and to allow comparisons in the preprocessor.
// Current library runtime version.
// - Gets bumped when the runtime makes changes to the interfaces between the
// generated code and runtime (things added/removed, etc).
#define GOOGLE_PROTOBUF_OBJC_VERSION 30002
// Minimum runtime version supported for compiling/running against.
// - Gets changed when support for the older generated code is dropped.
#define GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION 30001
// This is a legacy constant now frozen in time for old generated code. If
// GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION ever gets moved above 30001 then
// this should also change to break code compiled with an old runtime that
// can't be supported any more.
#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30001
......@@ -58,8 +58,50 @@ NSData *GPBEmptyNSData(void) {
return defaultNSData;
}
// -- About Version Checks --
// There's actually 3 places these checks all come into play:
// 1. When the generated source is compile into .o files, the header check
// happens. This is checking the protoc used matches the library being used
// when making the .o.
// 2. Every place a generated proto header is included in a developer's code,
// the header check comes into play again. But this time it is checking that
// the current library headers being used still support/match the ones for
// the generated code.
// 3. At runtime the final check here (GPBCheckRuntimeVersionsInternal), is
// called from the generated code passing in values captured when the
// generated code's .o was made. This checks that at runtime the generated
// code and runtime library match.
void GPBCheckRuntimeVersionSupport(int32_t objcRuntimeVersion) {
// NOTE: This is passing the value captured in the compiled code to check
// against the values captured when the runtime support was compiled. This
// ensures the library code isn't in a different framework/library that
// was generated with a non matching version.
if (GOOGLE_PROTOBUF_OBJC_VERSION < objcRuntimeVersion) {
// Library is too old for headers.
[NSException raise:NSInternalInconsistencyException
format:@"Linked to ProtocolBuffer runtime version %d,"
@" but code compiled needing atleast %d!",
GOOGLE_PROTOBUF_OBJC_VERSION, objcRuntimeVersion];
}
if (objcRuntimeVersion < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION) {
// Headers are too old for library.
[NSException raise:NSInternalInconsistencyException
format:@"Proto generation source compiled against runtime"
@" version %d, but this version of the runtime only"
@" supports back to %d!",
objcRuntimeVersion,
GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION];
}
}
// This api is no longer used for version checks. 30001 is the last version
// using this old versioning model. When that support is removed, this function
// can be removed (along with the declaration in GPBUtilities_PackagePrivate.h).
void GPBCheckRuntimeVersionInternal(int32_t version) {
if (version != GOOGLE_PROTOBUF_OBJC_GEN_VERSION) {
GPBInternalCompileAssert(GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION == 30001,
time_to_remove_this_old_version_shim);
if (version != GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION) {
[NSException raise:NSInternalInconsistencyException
format:@"Linked to ProtocolBuffer runtime version %d,"
@" but code compiled with version %d!",
......
......@@ -50,6 +50,17 @@ CF_EXTERN_C_BEGIN
// These two are used to inject a runtime check for version mismatch into the
// generated sources to make sure they are linked with a supporting runtime.
void GPBCheckRuntimeVersionSupport(int32_t objcRuntimeVersion);
GPB_INLINE void GPB_DEBUG_CHECK_RUNTIME_VERSIONS() {
// NOTE: By being inline here, this captures the value from the library's
// headers at the time the generated code was compiled.
#if defined(DEBUG) && DEBUG
GPBCheckRuntimeVersionSupport(GOOGLE_PROTOBUF_OBJC_VERSION);
#endif
}
// Legacy version of the checks, remove when GOOGLE_PROTOBUF_OBJC_GEN_VERSION
// goes away (see more info in GPBBootstrap.h).
void GPBCheckRuntimeVersionInternal(int32_t version);
GPB_INLINE void GPBDebugCheckRuntimeVersion() {
#if defined(DEBUG) && DEBUG
......
......@@ -13,8 +13,11 @@
#import "GPBProtocolBuffers.h"
#endif
#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
// @@protoc_insertion_point(imports)
......
......@@ -39,7 +39,7 @@ static GPBFileDescriptor *GPBAnyRoot_FileDescriptor(void) {
// about thread safety of the singleton.
static GPBFileDescriptor *descriptor = NULL;
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
GPB_DEBUG_CHECK_RUNTIME_VERSIONS();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
......
......@@ -13,8 +13,11 @@
#import "GPBProtocolBuffers.h"
#endif
#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
// @@protoc_insertion_point(imports)
......
......@@ -43,7 +43,7 @@ static GPBFileDescriptor *GPBApiRoot_FileDescriptor(void) {
// about thread safety of the singleton.
static GPBFileDescriptor *descriptor = NULL;
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
GPB_DEBUG_CHECK_RUNTIME_VERSIONS();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
......
......@@ -13,8 +13,11 @@
#import "GPBProtocolBuffers.h"
#endif
#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
// @@protoc_insertion_point(imports)
......
......@@ -39,7 +39,7 @@ static GPBFileDescriptor *GPBDurationRoot_FileDescriptor(void) {
// about thread safety of the singleton.
static GPBFileDescriptor *descriptor = NULL;
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
GPB_DEBUG_CHECK_RUNTIME_VERSIONS();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
......
......@@ -13,8 +13,11 @@
#import "GPBProtocolBuffers.h"
#endif
#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
// @@protoc_insertion_point(imports)
......
......@@ -39,7 +39,7 @@ static GPBFileDescriptor *GPBEmptyRoot_FileDescriptor(void) {
// about thread safety of the singleton.
static GPBFileDescriptor *descriptor = NULL;
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
GPB_DEBUG_CHECK_RUNTIME_VERSIONS();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
......
......@@ -13,8 +13,11 @@
#import "GPBProtocolBuffers.h"
#endif
#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
// @@protoc_insertion_point(imports)
......
......@@ -39,7 +39,7 @@ static GPBFileDescriptor *GPBFieldMaskRoot_FileDescriptor(void) {
// about thread safety of the singleton.
static GPBFileDescriptor *descriptor = NULL;
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
GPB_DEBUG_CHECK_RUNTIME_VERSIONS();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
......
......@@ -13,8 +13,11 @@
#import "GPBProtocolBuffers.h"
#endif
#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
// @@protoc_insertion_point(imports)
......
......@@ -39,7 +39,7 @@ static GPBFileDescriptor *GPBSourceContextRoot_FileDescriptor(void) {
// about thread safety of the singleton.
static GPBFileDescriptor *descriptor = NULL;
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
GPB_DEBUG_CHECK_RUNTIME_VERSIONS();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
......
......@@ -13,8 +13,11 @@
#import "GPBProtocolBuffers.h"
#endif
#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
// @@protoc_insertion_point(imports)
......
......@@ -40,7 +40,7 @@ static GPBFileDescriptor *GPBStructRoot_FileDescriptor(void) {
// about thread safety of the singleton.
static GPBFileDescriptor *descriptor = NULL;
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
GPB_DEBUG_CHECK_RUNTIME_VERSIONS();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
......
......@@ -13,8 +13,11 @@
#import "GPBProtocolBuffers.h"
#endif
#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
// @@protoc_insertion_point(imports)
......
......@@ -39,7 +39,7 @@ static GPBFileDescriptor *GPBTimestampRoot_FileDescriptor(void) {
// about thread safety of the singleton.
static GPBFileDescriptor *descriptor = NULL;
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
GPB_DEBUG_CHECK_RUNTIME_VERSIONS();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
......
......@@ -13,8 +13,11 @@
#import "GPBProtocolBuffers.h"
#endif
#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
// @@protoc_insertion_point(imports)
......
......@@ -43,7 +43,7 @@ static GPBFileDescriptor *GPBTypeRoot_FileDescriptor(void) {
// about thread safety of the singleton.
static GPBFileDescriptor *descriptor = NULL;
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
GPB_DEBUG_CHECK_RUNTIME_VERSIONS();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
......
......@@ -13,8 +13,11 @@
#import "GPBProtocolBuffers.h"
#endif
#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30002
#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30002
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
#if 30002 < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.
#endif
// @@protoc_insertion_point(imports)
......
......@@ -39,7 +39,7 @@ static GPBFileDescriptor *GPBWrappersRoot_FileDescriptor(void) {
// about thread safety of the singleton.
static GPBFileDescriptor *descriptor = NULL;
if (!descriptor) {
GPBDebugCheckRuntimeVersion();
GPB_DEBUG_CHECK_RUNTIME_VERSIONS();
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf"
objcPrefix:@"GPB"
syntax:GPBFileSyntaxProto3];
......
......@@ -51,10 +51,8 @@ namespace objectivec {
namespace {
// This is also found in GPBBootstrap.h, and needs to be kept in sync. It
// is the version check done to ensure generated code works with the current
// runtime being used.
const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30002;
// This is also found in GPBBootstrap.h, and needs to be kept in sync.
const int32 GOOGLE_PROTOBUF_OBJC_VERSION = 30002;
const char* kHeaderExtension = ".pbobjc.h";
......@@ -192,13 +190,19 @@ void FileGenerator::GenerateHeader(io::Printer *printer) {
// Add some verification that the generated code matches the source the
// code is being compiled with.
// NOTE: This captures the raw numeric values at the time the generator was
// compiled, since that will be the versions for the ObjC runtime at that
// time. The constants in the generated code will then get their values at
// at compile time (so checking against the headers being used to compile).
printer->Print(
"#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != $protoc_gen_objc_version$\n"
"#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources.\n"
"#if GOOGLE_PROTOBUF_OBJC_VERSION < $google_protobuf_objc_version$\n"
"#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.\n"
"#endif\n"
"#if $google_protobuf_objc_version$ < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION\n"
"#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.\n"
"#endif\n"
"\n",
"protoc_gen_objc_version",
SimpleItoa(GOOGLE_PROTOBUF_OBJC_GEN_VERSION));
"google_protobuf_objc_version", SimpleItoa(GOOGLE_PROTOBUF_OBJC_VERSION));
// #import any headers for "public imports" in the proto file.
{
......@@ -392,7 +396,7 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
" // about thread safety and initialization of registry.\n"
" static GPBExtensionRegistry* registry = nil;\n"
" if (!registry) {\n"
" GPBDebugCheckRuntimeVersion();\n"
" GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n"
" registry = [[GPBExtensionRegistry alloc] init];\n");
printer->Indent();
......@@ -487,7 +491,7 @@ void FileGenerator::GenerateSource(io::Printer *printer) {
" // about thread safety of the singleton.\n"
" static GPBFileDescriptor *descriptor = NULL;\n"
" if (!descriptor) {\n"
" GPBDebugCheckRuntimeVersion();\n");
" GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n");
if (vars["objc_prefix"].size() > 0) {
printer->Print(
vars,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment