Skip to content

Symbol mangling fails when a pod has both a class and a macro with the same name #31

@IAmConorNolan

Description

@IAmConorNolan

Description

When a pod defines both a class and a macro with the same name, cocoapods-mangle's preprocessor-based approach causes compilation failures. The -D flag replaces ALL occurrences of the symbol, breaking macro definitions.

Concrete Example: Ably Pod

The Ably pod (v1.2.33) has both:

  1. A class named ARTLog:
// Source/include/Ably/ARTLog.h
@interface ARTLog : NSObject
@property (nonatomic) ARTLogLevel logLevel;
- (void)log:(NSString *)message withLevel:(ARTLogLevel)level;
@end
  1. A macro named ARTLog:
// Source/PrivateHeaders/Ably/ARTInternalLog.h
#define ARTLog(_logger, _level, _format, ...) \
    [_logger logWithLevel:_level file:__FILE__ line:__LINE__ format:_format, ##__VA_ARGS__]

The Problem

When cocoapods-mangle generates -DARTLog=MySDKSDK_ARTLog, the preprocessor replaces BOTH:

What happens to the class (✅ This is desired):

@interface MySDKSDK_ARTLog : NSObject  // Good - class gets renamed

What happens to the macro (❌ This breaks):

#define MySDKSDK_ARTLog(_logger, _level, _format, ...) \  // Bad - invalid macro name!
    [_logger logWithLevel:_level file:__FILE__ line:__LINE__ format:_format, ##__VA_ARGS__]

The macro definition becomes invalid because MySDKSDK_ARTLog(...) is not valid preprocessor syntax for a function-like macro definition.

Compilation Error

/Users/.../Pods/Ably/Source/include/Ably/ARTClientOptions.h:55:34: error: unknown type name 'ARTLog'
@property (nonatomic, readwrite) ARTLog *logHandler;
                                 ^

This happens because the broken macro definition prevents proper compilation of the headers.

Why This Is Challenging

Preprocessor defines (-D) operate at the text substitution level before the compiler understands the difference between classes and macros. There's no way to tell the preprocessor "only replace ARTLog when it's a class reference, not when it's a macro definition."

Workaround

We have to monkey-patch the pod to rename the macro:

# In Podfile
post_install do |installer|
  header_path = "#{__dir__}/Pods/Ably/Source/PrivateHeaders/Ably/ARTInternalLog.h"

  if File.exist?(header_path)
    content = File.read(header_path)
    # Rename macro from ARTLog to ARTLogMacro
    content.gsub!(/^#define ARTLog\(/, '#define ARTLogMacro(')
    content.gsub!(/\bARTLog\(logger, ARTLogLevel/, 'ARTLogMacro(logger, ARTLogLevel')
    File.write(header_path, content)
  end
end

This is a fundamental limitation of using preprocessor defines for symbol mangling. The issue cannot be fully solved without either:

  • Changing the mangling implementation approach
  • Requiring source modifications to affected pods
  • Providing robust detection and workaround mechanisms

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions