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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions