Shared Library constructor in XCode 16.4 and 26 linker/runtime

GCC's shared library constructor technique has ceased working with the tool chain provided with XCode 16.4 and XCode 26. This is the GCC attribute:

__attribute__((constructor))

Example use:

void aConstructor(void) __attribute__((constructor));

void aConstructor(void) 
{ 
    printf("Called aConstructor\n");
}

In our case aConstructor() was not called.

Answered by DTS Engineer in 867985022
I clicked 'Accepted Answer' by mistake and can't undo it?

Indeed )-: See tip 12 in Quinn’s Top Ten DevForums Tips for more about that.

Note that the comment facility here is failing to post comments

Well, they post but there’s a bug causing them to not show up immediately (i. 98940414)-: In general, I recommend that you reply as a reply. See tip 5 for more on that.


Coming back to your technical issue, this seems to be working for me in Xcode 26.1. Here’s what I did:

  1. Using Xcode 26.1 on macOS 15.7.1, I created a new project from the macOS > Command Line Tool template, selecting C as the language.

  2. I changed main.c to this:

    #include <stdlib.h>
    #include <stdio.h>
    
    __attribute__((constructor(200))) void foo(void);
    __attribute__((constructor(101))) void bar(void);
    
    void foo(void) {
        printf("foo\n");
    }
    
    void bar(void) {
        printf("bar\n");
    }
    
    int main(int argc, char **argv) {
        #pragma unused(argc)
        #pragma unused(argv)
        printf("main\n");
        return EXIT_SUCCESS;
    }
    

    This is based on the example in the latest Clang docs [1].

  3. I ran my program. It printed:

    bar
    foo
    main
    

    which is what I expected: The constructors ran before main and in the order specified by the attribute.

  4. I created a new target based on the macOS > Library template, selecting Plain C/C++ Library in the Framework popup and Dynamic in the Type popup. I called this Waffle, resulting in libWaffle.dylib.

  5. I created the following C source file and added it to that target:

    #include <stdio.h>
    
    __attribute__((constructor(200))) void fooWaffle(void);
    __attribute__((constructor(101))) void barWaffle(void);
    
    void fooWaffle(void) {
        printf("fooWaffle\n");
    }
    
    void barWaffle(void) {
        printf("barWaffle\n");
    }
    
    extern void varnishWafflesNow(void);
    
    extern void varnishWafflesNow(void) {
        printf("varnishWafflesNow\n");
    }
    
  6. I added the libWaffle.dylib library to the command-line tool target.

  7. I changed the bottom of main.c like so:

    … as above …
    
    extern void varnishWafflesNow(void);
    
    int main(int argc, char **argv) {
        #pragma unused(argc)
        #pragma unused(argv)
        printf("main\n");
        varnishWafflesNow();
        return EXIT_SUCCESS;
    }
    

    Note that I copy’n’pasted the prototype to avoid faffing around with headers (-:

  8. I ran the tool. It printed:

    barWaffle
    fooWaffle
    bar
    foo
    main
    varnishWafflesNow
    

This seems right to me. The library constructors ran first, then the main executable constructors, and then main.

Please repeat these steps in your environment to make sure you get the same results. If so, you have a working and a non-working example, and you can explore the differences.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] https://clang.llvm.org/docs/AttributeReference.html#constructor-destructor

Accepted Answer

I’d like to clarify your setup here. Are you using GCC proper? Or using the Clang that’s built in to Xcode with an attribute that just happened to originate in GCC?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

(Sorry I clicked 'Accepted Answer' by mistake and can't undo it?)

Hi Quinn - we are using XCode's inbuilt toolchain. The constructor was called when we used the previous XCode toolchain, but is not called when built with XCode 16.4/26 toolchains.

(Note that the comment facility here is failing to post comments, only replies)

I clicked 'Accepted Answer' by mistake and can't undo it?

Indeed )-: See tip 12 in Quinn’s Top Ten DevForums Tips for more about that.

Note that the comment facility here is failing to post comments

Well, they post but there’s a bug causing them to not show up immediately (i. 98940414)-: In general, I recommend that you reply as a reply. See tip 5 for more on that.


Coming back to your technical issue, this seems to be working for me in Xcode 26.1. Here’s what I did:

  1. Using Xcode 26.1 on macOS 15.7.1, I created a new project from the macOS > Command Line Tool template, selecting C as the language.

  2. I changed main.c to this:

    #include <stdlib.h>
    #include <stdio.h>
    
    __attribute__((constructor(200))) void foo(void);
    __attribute__((constructor(101))) void bar(void);
    
    void foo(void) {
        printf("foo\n");
    }
    
    void bar(void) {
        printf("bar\n");
    }
    
    int main(int argc, char **argv) {
        #pragma unused(argc)
        #pragma unused(argv)
        printf("main\n");
        return EXIT_SUCCESS;
    }
    

    This is based on the example in the latest Clang docs [1].

  3. I ran my program. It printed:

    bar
    foo
    main
    

    which is what I expected: The constructors ran before main and in the order specified by the attribute.

  4. I created a new target based on the macOS > Library template, selecting Plain C/C++ Library in the Framework popup and Dynamic in the Type popup. I called this Waffle, resulting in libWaffle.dylib.

  5. I created the following C source file and added it to that target:

    #include <stdio.h>
    
    __attribute__((constructor(200))) void fooWaffle(void);
    __attribute__((constructor(101))) void barWaffle(void);
    
    void fooWaffle(void) {
        printf("fooWaffle\n");
    }
    
    void barWaffle(void) {
        printf("barWaffle\n");
    }
    
    extern void varnishWafflesNow(void);
    
    extern void varnishWafflesNow(void) {
        printf("varnishWafflesNow\n");
    }
    
  6. I added the libWaffle.dylib library to the command-line tool target.

  7. I changed the bottom of main.c like so:

    … as above …
    
    extern void varnishWafflesNow(void);
    
    int main(int argc, char **argv) {
        #pragma unused(argc)
        #pragma unused(argv)
        printf("main\n");
        varnishWafflesNow();
        return EXIT_SUCCESS;
    }
    

    Note that I copy’n’pasted the prototype to avoid faffing around with headers (-:

  8. I ran the tool. It printed:

    barWaffle
    fooWaffle
    bar
    foo
    main
    varnishWafflesNow
    

This seems right to me. The library constructors ran first, then the main executable constructors, and then main.

Please repeat these steps in your environment to make sure you get the same results. If so, you have a working and a non-working example, and you can explore the differences.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] https://clang.llvm.org/docs/AttributeReference.html#constructor-destructor

Hi Quinn - thanks for your comprehensive replies. (I've performed the same role for Qualcomm's Augmented Reality Toolkit in the past so I appreciate the time it takes).

I'll follow through your example. The only obvious difference I can see from inspection is the passing of the constant integer to the constructor() macro.

We have a work-around which is to explicitly call the initialisation method before doing anything else with the library, but it'd be good to know if this is the issue for others.

= Martin =

I’m glad to hear you’re making progress here.

The only obvious difference … is the passing of the constant integer to the constructor

I dug my test project out of the trash and removed those priority values. It still exhibits correct behaviour [1].

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Although the order of foo{,Waffle} and bar{,Waffle} lines were swapped.

Shared Library constructor in XCode 16.4 and 26 linker/runtime
 
 
Q