Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AdsrEnvelope has multiple definitions when compiling C++ patch with .cpp file provided #118

Open
TarkanAl-Kazily opened this issue Apr 23, 2023 · 2 comments
Assignees

Comments

@TarkanAl-Kazily
Copy link

The way the AdsrEnvelope.h header is written, the specialized implementations for Linear and Exponential envelope types get defined multiple times when building a patch that uses a .cpp file, resulting in the Patch elf failing the linker step.

This is rather simple to reproduce just with two files implementing an empty Patch that just creates an AdsrEnvelope:

EnvelopeBugPatch.hpp

#ifndef __EnvelopeBugPatch_hpp__
#define __EnvelopeBugPatch_hpp__

#include "Patch.h"
#include "AdsrEnvelope.h"

class EnvelopeBugPatch : public Patch {
public:
  EnvelopeBugPatch() {
    env = LinearAdsrEnvelope::create(getSampleRate());
  }

  ~EnvelopeBugPatch() {
    LinearAdsrEnvelope::destroy(env);
  }

  void processAudio(AudioBuffer &buffer) override;

private:
  LinearAdsrEnvelope *env;
};

#endif // __EnvelopeBugPatch_hpp__

EnvelopeBugPatch.cpp

#include "EnvelopeBugPatch.hpp"

void EnvelopeBugPatch::processAudio(AudioBuffer &buffer) {}

The result when compiling these is a linker error:

$ make PATCHNAME=EnvelopeBug clean patch
Building patch EnvelopeBug
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: ./Build/PatchProgram.o (symbol from plugin): in function `onMidiCallback(unsigned char, unsigned char, unsigned char, unsigned char)':
(.text+0x0): multiple definition of `AdsrEnvelope<true>::increment(float, float)'; ./Build/EnvelopeBugPatch.o (symbol from plugin):(.text+0x0): first defined here
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: ./Build/PatchProgram.o (symbol from plugin): in function `onMidiCallback(unsigned char, unsigned char, unsigned char, unsigned char)':
(.text+0x0): multiple definition of `AdsrEnvelope<true>::decrement(float, float)'; ./Build/EnvelopeBugPatch.o (symbol from plugin):(.text+0x0): first defined here
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: ./Build/PatchProgram.o (symbol from plugin): in function `onMidiCallback(unsigned char, unsigned char, unsigned char, unsigned char)':
(.text+0x0): multiple definition of `AdsrEnvelope<false>::increment(float, float)'; ./Build/EnvelopeBugPatch.o (symbol from plugin):(.text+0x0): first defined here
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: ./Build/PatchProgram.o (symbol from plugin): in function `onMidiCallback(unsigned char, unsigned char, unsigned char, unsigned char)':
(.text+0x0): multiple definition of `AdsrEnvelope<false>::decrement(float, float)'; ./Build/EnvelopeBugPatch.o (symbol from plugin):(.text+0x0): first defined here
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: ./Build/PatchProgram.o (symbol from plugin): in function `onMidiCallback(unsigned char, unsigned char, unsigned char, unsigned char)':
(.text+0x0): multiple definition of `AdsrEnvelope<true>::calculateIncrement(float, float, float)'; ./Build/EnvelopeBugPatch.o (symbol from plugin):(.text+0x0): first defined here
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: ./Build/PatchProgram.o (symbol from plugin): in function `onMidiCallback(unsigned char, unsigned char, unsigned char, unsigned char)':
(.text+0x0): multiple definition of `AdsrEnvelope<false>::calculateIncrement(float, float, float)'; ./Build/EnvelopeBugPatch.o (symbol from plugin):(.text+0x0): first defined here
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: ./Build/PatchProgram.o (symbol from plugin): in function `onMidiCallback(unsigned char, unsigned char, unsigned char, unsigned char)':
(.text+0x0): multiple definition of `AdsrEnvelope<false>::MINLEVEL'; ./Build/EnvelopeBugPatch.o (symbol from plugin):(.text+0x0): first defined here
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: ./Build/PatchProgram.o (symbol from plugin): in function `onMidiCallback(unsigned char, unsigned char, unsigned char, unsigned char)':
(.text+0x0): multiple definition of `AdsrEnvelope<true>::MINLEVEL'; ./Build/EnvelopeBugPatch.o (symbol from plugin):(.text+0x0): first defined here
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: warning: Build/patch.elf has a LOAD segment with RWX permissions
collect2: error: ld returned 1 exit status
make[1]: *** [compile.mk:179: Build/patch.elf] Error 1
make: *** [Makefile:110: patch] Error 2
TarkanAl-Kazily added a commit to TarkanAl-Kazily/OwlProgram that referenced this issue Apr 23, 2023
This fixes the linker issue where multiple definitions are present for
the specialized AdsrEnvelope functions, by moving these specialized
functions into a new .cpp file.

Because these are specialized for specific types, they shouldn't be
included in multiple source files.

Tested using the repro steps in issue RebelTechnology#118.
@antisvin
Copy link
Collaborator

There are 2 correct ways to use fully specialiazed templates - either in source file as described here, or keep them in the header file with inline keyword added. Moving them to a CPP file is probably preferable, as this would compile them just once when building static OWL library.

@TarkanAl-Kazily
Copy link
Author

Here there are also two specialized templates used for a constant for which inline can't be used, so I took the approach to just create a new file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants