Undefined symbols for architecture arm64

Hi guys.
I just started dipping my toes in JUCE, so forgive me if it’s a trivial issue. I searched in the forum without finding anything helpful.

I’m adding some basic oscillator code I wrote to my JUCE plugin. The oscillator class is declared in a separate Oscillator.hpp file and its member functions’ definitions are in a Oscillator.cpp file. Both files have been added to the project using the Projucer’s File Explorer.
The header is correctly included in the PluginProcessor.h file.
I can build without issue when I add the oscillator member to the Processor class, but as soon as I call any of the Oscillator’s member functions, I get this error when building:

ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I really can’t wrap my head around this. I’m also new to XCode, so that doesn’t help.

Any idea on how to solve this? I already tried the solutions that pop out when Googling the issue, but nothing helped.

Thanks!

I’m on a MacBook Pro 14" with M1 Pro.

Is this AAX and Xcode 13.3? Disable arm64 for the AAX build (since Xcode 13.3) – unfortunately there’s no way to do that in ProJucer only for a single format.

Rail

No. I’m only building VST3, AU and standalone and I’m on 13.2.1.

I think you only copied parts of the linker error message, to narrow it down a bit it would be useful to see which symbols are not found by the linker.

Generally, an error like that occurs if something was declared but no definitition could be found in any translation unit that the linker tries to combine. In your case it might be that you e.g. declared a member function in Oscillator.hpp and missed to define it in Oscillator.cpp. Another possible explanation could be that for some reasons Oscillator.cpp is not compiled at all.

This is the full message:

Ld /Users/jacopolovatello/Library/Developer/Xcode/DerivedData/Scirocco-ajoseqgccatdaxbglzrsbcbwjwci/Build/Intermediates.noindex/Scirocco.build/Debug/Scirocco\ -\ VST3.build/Objects-normal/arm64/Binary/Scirocco normal arm64 (in target 'Scirocco - VST3' from project 'Scirocco')
    cd /Users/jacopolovatello/Dev/eftilo/projects/Scirocco/Builds/MacOSX
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -target arm64-apple-macos10.11 -bundle -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk -L/Users/jacopolovatello/Dev/eftilo/projects/Scirocco/Builds/MacOSX/build/Debug -F/Users/jacopolovatello/Dev/eftilo/projects/Scirocco/Builds/MacOSX/build/Debug -filelist /Users/jacopolovatello/Library/Developer/Xcode/DerivedData/Scirocco-ajoseqgccatdaxbglzrsbcbwjwci/Build/Intermediates.noindex/Scirocco.build/Debug/Scirocco\ -\ VST3.build/Objects-normal/arm64/Scirocco.LinkFileList -Xlinker -object_path_lto -Xlinker /Users/jacopolovatello/Library/Developer/Xcode/DerivedData/Scirocco-ajoseqgccatdaxbglzrsbcbwjwci/Build/Intermediates.noindex/Scirocco.build/Debug/Scirocco\ -\ VST3.build/Objects-normal/arm64/Scirocco_lto.o -Xlinker -no_deduplicate -stdlib\=libc++ -bundle -lScirocco -framework Accelerate -framework AudioToolbox -framework Carbon -framework Cocoa -framework CoreAudio -framework CoreAudioKit -framework CoreMIDI -framework DiscRecording -framework Foundation -framework IOKit -framework QuartzCore -Xlinker -dependency_info -Xlinker /Users/jacopolovatello/Library/Developer/Xcode/DerivedData/Scirocco-ajoseqgccatdaxbglzrsbcbwjwci/Build/Intermediates.noindex/Scirocco.build/Debug/Scirocco\ -\ VST3.build/Objects-normal/arm64/Scirocco_dependency_info.dat -o /Users/jacopolovatello/Library/Developer/Xcode/DerivedData/Scirocco-ajoseqgccatdaxbglzrsbcbwjwci/Build/Intermediates.noindex/Scirocco.build/Debug/Scirocco\ -\ VST3.build/Objects-normal/arm64/Binary/Scirocco

Undefined symbols for architecture arm64:
  "eftilo::BufNaiveOscillator<float>::BufNaiveOscillator()", referenced from:
      SciroccoAudioProcessor::SciroccoAudioProcessor() in libScirocco.a(PluginProcessor.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I double checked and all the member functions are correctly declared and defined. I also tried to explicitly add for compilation the .cpp file, so that should be compiled(?).

Interestingly enough, if in my PluginProcessor I include Oscillator.cpp instead of Oscillator.hpp, the build goes through. Not sure what does this mean.

Okay, it seems like you implemented a class template. Class template need a slightly different treatment than classes as they do not finally describe a class but rather are a template that can be used to describe a lot of similar classes but with different template arguments.

I assume your code looks somewhat like that:

Oscillator.hpp

namespace eftilo
{

template <typename SampleType>
BufNaiveOscillator
{
public:
    BufNaiveOscillator();

    void process (juce::dsp::ProcessContextReplacing<SampleType>& context);
}
}

Oscillator.cpp

#include "Oscillator.hpp"

namespace eftilo
{

template <typename SampleType> 
BufNaiveOscillator::BufNaiveOscillator()
{
    // do some setup
}

template <typename SampleType> 
void BufNaiveOscillator::process (juce::dsp::ProcessContextReplacing<SampleType>& context)
{
    // do some processing
}
}

Now, if you are compiling the project, the compiler will compile PluginProcessor.cpp and Oscillator.cpp in parallel, individually from each other. PluginProcessor references a specific instantiation of the template where SampleType is float. It does however not know at that point what the function eftilo::BufNaiveOscillator<float>::BufNaiveOscillator() looks like as it’s not fully described in the scope of that file as the compiler sees it, so it leaves a note for the linker (ld) to look for it somewhere else after all files have been compiled. In parallel, another compilation process parses Oscillator.cpp. All it finds in this file is a definition of the implementation of the details of the class template you declared in Oscillator.hpp but no hint for what template parameter choices it should actually compile this class. So it will actually compile nothing. After that the linker looks for some compiled version of eftilo::BufNaiveOscillator<float>::BufNaiveOscillator() and fails to find it. This is why you get this error message.

Now how to solve this?
There are two choices. The first is to include a list of all template instantiations that the class template should actually be compiled for in the translation unit. This means you could add

template class BufNaiveOscillator<float>;
template class BufNaiveOscillator<double>;

at the end of your Oscillator.cpp file so that now the compiler sees that it should compile the template defined above for this two specific types. Now the linker will be able to resolve a reference to BufNaiveOscillator<float>, as this version has explicitly been compiled. It will still give you an error if you e.g. referenced BufNaiveOscillator<int> in your code, as this version has not been compiled anywhere.

The other option that is used frequently is to define your class template header-only. This means, instead of splitting it up into a .hpp header file and a separately compiled .cpp translation unit, you can just put the whole definition right into the header. Now, every translation unit that references your template can see the full definition and can compile the version for your template type of choice along with the surrounding code.

I hope my guess was right and this helps you :wink:

3 Likes

Of course. That makes sense.
I’m used to basically only code pure C and very simple C++, so all this concepts still confuse me at times.

Thank you very much for the solution but most importantly for the super detailed explanation, it worked right away!

1 Like