Анализ __cxa_pure_virtual error

Я пишу проект с моими собственными библиотеками, написанными на C, в смешанном C / C ++ проекте, и я хотел бы использовать с соответствующими настройками некоторые готовые библиотеки Arduino.

Я начал с удаления зависимостей Arduino.h, используя мои библиотеки портов в C вместо Arduino ecc, и каждая библиотека C работает нормально в среде C / C ++. Это также хорошо компилируется.

Затем компоновщик завершается со следующим сообщением:

[...]Debug\Makefile(171,1): error: recipe for target 'oled_basic_gcc.elf' failed
Adafruit_GFX.o:(.rodata._ZTV12Adafruit_GFX[vtable for Adafruit_GFX]+0x4): undefined reference to `__cxa_pure_virtual'

РЕДАКТИРОВАТЬ: это полный журнал

------ Build started: Project: oled_basic_gcc, Configuration: Debug AVR ------
Build started.
Project "oled_basic_gcc.cppproj" (default targets):
Target "PreBuildEvent" skipped, due to false condition; ('$(PreBuildEvent)'!='') was evaluated as (''!='').
Target "CoreBuild" in file "C:\Program Files (x86)\Atmel\Studio\7.0\Vs\Compiler.targets" from project "C:\Users\thexeno\Downloads\oled_basic_gcc\oled_basic_gcc\oled_basic_gcc.cppproj" (target "Build" depends on it):
Task "RunCompilerTask"Shell Utils Path C:\Program Files (x86)\Atmel\Studio\7.0\shellUtils
C:\Program Files (x86)\Atmel\Studio\7.0\shellUtils\make.exe all --jobs 4 --output-sync
Building target: oled_basic_gcc.elf
Invoking: AVR8/GNU Linker : 5.4.0
"C:\Program Files (x86)\Atmel\Studio\7.0\toolchain\avr8\avr8-gnu-toolchain\bin\avr-g++.exe" -o oled_basic_gcc.elf  Adafruit_GFX.o Adafruit_SSD1306.o glcdfont.o i2c.o main.o port.o task.o timers.o usart.o   -Wl,-Map="oled_basic_gcc.map" -Wl,--start-group -Wl,-lm  -Wl,--end-group -Wl,--gc-sections -mmcu=atmega328p -B "C:\Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.1.130\gcc\dev\atmega328p"C:\Users\thexeno\Downloads\oled_basic_gcc\oled_basic_gcc\Debug\Makefile(171,1): error: recipe for target 'oled_basic_gcc.elf' failed
Adafruit_GFX.o:(.rodata._ZTV12Adafruit_GFX[vtable for Adafruit_GFX]+0x4): undefined reference to `__cxa_pure_virtual'
collect2.exe(0,0): error: ld returned 1 exit status
make: *** [oled_basic_gcc.elf] Error 1
The command exited with code 2.
Done executing task "RunCompilerTask" -- FAILED.
Done building target "CoreBuild" in project "oled_basic_gcc.cppproj" -- FAILED.
Done building project "oled_basic_gcc.cppproj" -- FAILED.

Build FAILED.
========== Build: 0 succeeded or up-to-date, 1 failed, 0 skipped ==========

И я думаю, что это связано с некоторым переопределением класса или подобными вещами, что, по-видимому, происходит только один раз в моем коде, по крайней мере, в afaik:

Это заголовок измененного файла Adafruit_GFX.h, в котором, хотя только первое определение функции вызывает проблему, поскольку теоретически это единственный виртуализированный файл Adafruit_SSD1306:

class Adafruit_GFX {

public:

Adafruit_GFX(int16_t w, int16_t h); // Constructor

// This MUST be defined by the subclass:
virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0;

// TRANSACTION API / CORE DRAW API
// These MAY be overridden by the subclass to provide device-specific
// optimized code.  Otherwise 'generic' versions are used.
virtual void startWrite(void);
virtual void writePixel(int16_t x, int16_t y, uint16_t color);
virtual void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
virtual void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
virtual void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
virtual void endWrite(void);

// CONTROL API
// These MAY be overridden by the subclass to provide device-specific
// optimized code.  Otherwise 'generic' versions are used.
virtual void setRotation(uint8_t r);
virtual void invertDisplay(boolean i);

// BASIC DRAW API
// These MAY be overridden by the subclass to provide device-specific
// optimized code.  Otherwise 'generic' versions are used.
virtual void
// It's good to implement those, even if using transaction API
drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color),
drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color),
fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color),
fillScreen(uint16_t color),
// Optional and probably not necessary to change
drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color),
drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);

// These exist only with Adafruit_GFX (no subclass overrides)
void
drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color),
drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
uint16_t color),
fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color),
fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,
int16_t delta, uint16_t color),
drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
int16_t x2, int16_t y2, uint16_t color),
fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
int16_t x2, int16_t y2, uint16_t color),
drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
int16_t radius, uint16_t color),
fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h,
int16_t radius, uint16_t color),
drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
int16_t w, int16_t h, uint16_t color),
drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
int16_t w, int16_t h, uint16_t color, uint16_t bg),
drawBitmap(int16_t x, int16_t y, uint8_t *bitmap,
int16_t w, int16_t h, uint16_t color),
drawBitmap(int16_t x, int16_t y, uint8_t *bitmap,
int16_t w, int16_t h, uint16_t color, uint16_t bg),
drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
int16_t w, int16_t h, uint16_t color),
drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
int16_t w, int16_t h),
drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap,
int16_t w, int16_t h),
drawGrayscaleBitmap(int16_t x, int16_t y,
const uint8_t bitmap[], const uint8_t mask[],
int16_t w, int16_t h),
drawGrayscaleBitmap(int16_t x, int16_t y,
uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h),
drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[],
int16_t w, int16_t h),
drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap,
int16_t w, int16_t h),
drawRGBBitmap(int16_t x, int16_t y,
const uint16_t bitmap[], const uint8_t mask[],
int16_t w, int16_t h),
drawRGBBitmap(int16_t x, int16_t y,
uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h),
drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color,
uint16_t bg, uint8_t size),
setCursor(int16_t x, int16_t y),
setTextColor(uint16_t c),
setTextColor(uint16_t c, uint16_t bg),
setTextSize(uint8_t s),
setTextWrap(boolean w),
cp437(boolean x=true),
setFont(const GFXfont *f = NULL),
getTextBounds(char *string, int16_t x, int16_t y,
int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h),
getTextBounds(const __FlashStringHelper *s, int16_t x, int16_t y,
int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h);virtual void   write(uint8_t);int16_t height(void) const;
int16_t width(void) const;

uint8_t getRotation(void) const;

// get current cursor position (get rotation safe maximum values, using: width() for x, height() for y)
int16_t getCursorX(void) const;
int16_t getCursorY(void) const;

protected:
void
charBounds(char c, int16_t *x, int16_t *y,
int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy);
const int16_t
WIDTH, HEIGHT;   // This is the 'raw' display w/h - never changes
int16_t
_width, _height, // Display w/h as modified by current rotation
cursor_x, cursor_y;
uint16_t
textcolor, textbgcolor;
uint8_t
textsize,
rotation;
boolean
wrap,   // If set, 'wrap' text at right edge of display
_cp437; // If set, use correct CP437 charset (default is off)
GFXfont
*gfxFont;
};

Пока только эта функция должна использоваться виртуально:

Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h):
WIDTH(w), HEIGHT(h)
{
_width    = WIDTH;
_height   = HEIGHT;
rotation  = 0;
cursor_y  = cursor_x    = 0;
textsize  = 1;
textcolor = textbgcolor = 0xFFFF;
wrap      = true;
_cp437    = false;
gfxFont   = NULL;
}

А вот в файле Adafruit_SSD1306.cpp, где должно быть единственное использование такой виртуализации / наследия:

// initializer for I2C - we only indicate the reset pin!
Adafruit_SSD1306::Adafruit_SSD1306(int8_t reset) :
Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) {
sclk = dc = cs = sid = -1;
rst = reset;
}

Я думаю, что если здесь есть ошибка, это может быть причиной моих проблем.

0

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …