Accessing Xcode build symbols


Carl Hoefs
 

Xcode 11.3.1

How can I read Xcode build symbols (e.g., $(MARKETING_VERSION)) from within my macOS app?

-Carl


Alex Zavatone
 

You can set them to be an entry within a plist.

I did that for the build environment so that we can determine if an app is built for debug, test or release.

I’ll look for a sample and get back to you.

Alex Zavatone

On Aug 12, 2020, at 2:41 PM, Carl Hoefs <newslists@autonomy.caltech.edu> wrote:

Xcode 11.3.1

How can I read Xcode build symbols (e.g., $(MARKETING_VERSION)) from within my macOS app?

-Carl




Alex Zavatone
 


So, to expose the build configuration environment variable to the app, I enter it as above into the app’s info,plist.

The code below is most of the BuildEnvironment class that enables my old app to access it at runtime.


@interface BuildEnvironment ()
@property (class, nonatomic, strong) NSString *buildConfig;
@end

@implementation BuildEnvironment

static NSString *_buildConfig = nil;

// AZ - Added error checking and reporting.
+ (NSString *)buildEnvironment
{
    // This relies on a key in the info.plist called @"Build config" that is set to $(CONFIGURATION).
    NSString *buildEnvironmentKey = @"Build config";
    NSString *errorMessage = @"Error: There must be a key in the info.plist called @\"Build config\" that is set to $(CONFIGURATION) for this to work.";
    if (_buildConfig == nil) {
        BOOL buildKeyExists = [self keyExistsInInfoDictionary: buildEnvironmentKey];
        if (buildKeyExists) {
            _buildConfig = [[NSBundle mainBundle] objectForInfoDictionaryKey:buildEnvironmentKey];
        } else {
            _buildConfig = errorMessage;
        }
        
    }
    return self.buildConfig;
}

+ (BOOL)keyExistsInInfoDictionary:(NSString *)objectForInfoDictionaryKey
{
    NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
    NSArray *infoDictionaryKeys = [infoDictionary allKeys];
    BOOL keyExistsInDictionary = [infoDictionaryKeys containsObject:objectForInfoDictionaryKey];
    return keyExistsInDictionary;
}

+ (BOOL)isDebug
{
    BOOL myResult = [self.buildConfig isEqualToString:@"Debug"];
    return myResult;
}

+ (BOOL)isNotDebug
{
    BOOL myResult = ![BuildEnvironment isDebug];
    return myResult;
}

+ (BOOL)isRelease
{
    BOOL myResult = [self.buildConfig isEqualToString:@"Release"];
    return myResult;
}

+ (BOOL)isNotRelease
{
    BOOL myResult = ![BuildEnvironment isRelease];
    return myResult;
}

+ (BOOL)isTest
{
    BOOL myResult = [self.buildConfig isEqualToString:@"Test"];
    return myResult;
}

+ (BOOL)isNotTest
{
    BOOL myResult = ![BuildEnvironment isTest];
    return myResult;
}


// AZ These allow a developer to check for a name match on a build config
// and also allow us to check for any build config that may be added in the future.
+ (BOOL)isBuildConfig:(NSString *)buildConfigToCheckFor
{
    BOOL myResult = [[self.buildConfig lowercaseString] isEqualToString:[buildConfigToCheckFor lowercaseString]];
    return myResult;
}

+ (BOOL)isNotBuildConfig:(NSString *)buildConfigToCheckFor
{
    BOOL myResult = ![BuildEnvironment isBuildConfig:buildConfigToCheckFor];
    return myResult;
}

+ (NSString *)displayBuildConfig
{
    NSMutableString *buildConfig = [@"Build Configuration is: " mutableCopy];
    NSString *buildEnv = [self buildConfig];
    [buildConfig appendString:buildEnv];
    return buildConfig;
}
@end


On Aug 12, 2020, at 4:16 PM, Alex Zavatone via groups.io <zav@...> wrote:

You can set them to be an entry within a plist.

I did that for the build environment so that we can determine if an app is built for debug, test or release.

I’ll look for a sample and get back to you.

Alex Zavatone


On Aug 12, 2020, at 2:41 PM, Carl Hoefs <newslists@...> wrote:

Xcode 11.3.1

How can I read Xcode build symbols (e.g., $(MARKETING_VERSION)) from within my macOS app?

-Carl








Carl Hoefs
 

Alex,

Thanks for the very complete example! I got it working!

-Carl

On Aug 12, 2020, at 2:56 PM, Alex Zavatone via groups.io <zav@...> wrote:

<PastedGraphic-5.png>

So, to expose the build configuration environment variable to the app, I enter it as above into the app’s info,plist.

The code below is most of the BuildEnvironment class that enables my old app to access it at runtime.


@interface BuildEnvironment ()
@property (class, nonatomic, strong) NSString *buildConfig;
@end

@implementation BuildEnvironment

static NSString *_buildConfig = nil;

// AZ - Added error checking and reporting.
+ (NSString *)buildEnvironment
{
    // This relies on a key in the info.plist called @"Build config" that is set to $(CONFIGURATION).
    NSString *buildEnvironmentKey = @"Build config";
    NSString *errorMessage = @"Error: There must be a key in the info.plist called @\"Build config\" that is set to $(CONFIGURATION) for this to work.";
    if (_buildConfig == nil) {
        BOOL buildKeyExists = [self keyExistsInInfoDictionary: buildEnvironmentKey];
        if (buildKeyExists) {
            _buildConfig = [[NSBundle mainBundle] objectForInfoDictionaryKey:buildEnvironmentKey];
        } else {
            _buildConfig = errorMessage;
        }
        
    }
    return self.buildConfig;
}

+ (BOOL)keyExistsInInfoDictionary:(NSString *)objectForInfoDictionaryKey
{
    NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
    NSArray *infoDictionaryKeys = [infoDictionary allKeys];
    BOOL keyExistsInDictionary = [infoDictionaryKeys containsObject:objectForInfoDictionaryKey];
    return keyExistsInDictionary;
}

+ (BOOL)isDebug
{
    BOOL myResult = [self.buildConfig isEqualToString:@"Debug"];
    return myResult;
}

+ (BOOL)isNotDebug
{
    BOOL myResult = ![BuildEnvironment isDebug];
    return myResult;
}

+ (BOOL)isRelease
{
    BOOL myResult = [self.buildConfig isEqualToString:@"Release"];
    return myResult;
}

+ (BOOL)isNotRelease
{
    BOOL myResult = ![BuildEnvironment isRelease];
    return myResult;
}

+ (BOOL)isTest
{
    BOOL myResult = [self.buildConfig isEqualToString:@"Test"];
    return myResult;
}

+ (BOOL)isNotTest
{
    BOOL myResult = ![BuildEnvironment isTest];
    return myResult;
}


// AZ These allow a developer to check for a name match on a build config
// and also allow us to check for any build config that may be added in the future.
+ (BOOL)isBuildConfig:(NSString *)buildConfigToCheckFor
{
    BOOL myResult = [[self.buildConfig lowercaseString] isEqualToString:[buildConfigToCheckFor lowercaseString]];
    return myResult;
}

+ (BOOL)isNotBuildConfig:(NSString *)buildConfigToCheckFor
{
    BOOL myResult = ![BuildEnvironment isBuildConfig:buildConfigToCheckFor];
    return myResult;
}

+ (NSString *)displayBuildConfig
{
    NSMutableString *buildConfig = [@"Build Configuration is: " mutableCopy];
    NSString *buildEnv = [self buildConfig];
    [buildConfig appendString:buildEnv];
    return buildConfig;
}
@end


On Aug 12, 2020, at 4:16 PM, Alex Zavatone via groups.io <zav@...> wrote:

You can set them to be an entry within a plist.

I did that for the build environment so that we can determine if an app is built for debug, test or release.

I’ll look for a sample and get back to you.

Alex Zavatone


On Aug 12, 2020, at 2:41 PM, Carl Hoefs <newslists@...> wrote:

Xcode 11.3.1

How can I read Xcode build symbols (e.g., $(MARKETING_VERSION)) from within my macOS app?

-Carl









Bernie Maier
 

On Thu, 13 Aug 2020, at 7:16 AM, Alex Zavatone via groups.io wrote:
You can set them to be an entry within a plist.
That’s an interesting approach. It never occurred to me to do that. I usually set up a compiler argument to define a pre-processor symbol, but I’ve only ever needed to do that for languages in the C family. So (from memory) it’s one of the CFLAG-style compiler settings, you will probably need to quote it but you’ll want something that expands out into:

-D MARKETING_VERSION=“$(MARKETING_VERSION)"

The plist approach and class encapsulating that would scale up better and looks neater, but for one-offs the pre-processor might suffice.

Cheers,
Bernie

[…]

On Aug 12, 2020, at 2:41 PM, Carl Hoefs <newslists@autonomy.caltech.edu> wrote:

Xcode 11.3.1

How can I read Xcode build symbols (e.g., $(MARKETING_VERSION)) from within my macOS app?

-Carl