I am asking this question again as the mods decided to close my question here as a duplicate, within minutes of it being asked (and also down-voted!!). Now I have gone through all 33 answers of what was thought to be an answer to my solution, but it didn't help. So I am asking again.
I am trying to build a FreeSWITCH module to add text-to-speech functionality using AWS Polly & the AWS C++ SDK.
Dev environment is Debian 8, g++ 4.9.2. AWS C++ SDK is built using instructions here except that I turned off shared libs (produces .a lib files).
The AWS C++ SDK was built as recommended here (basically C++ code with C++ linkage). mod_polly.cpp is built with C++ linkage as well to produce mod_polly.so. It does refer to some C headers & functions. This was built as -
g++ -shared -o mod_polly.so -L/usr/local/lib/ -laws-cpp-sdk-polly -laws-cpp-sdk-core -fPIC -g -ggdb -std=c++11 -Wall -Werror -I/usr/src/freeswitch/src/include/ -I/usr/src/freeswitch/libs/libteletone/src/ mod_polly.cpp
Source below -
extern "C" {
#include <switch.h>
}
#include <fstream>
#define BIG_ENDIAN_SYSTEM (*(uint16_t *)"\0\xff" < 0x100)
#define REVERSE_BYTES(...) do for(size_t REVERSE_BYTES=0; REVERSE_BYTES<sizeof(__VA_ARGS__)>>1; ++REVERSE_BYTES)\
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES],\
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES],\
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES];\
while(0)
#include <aws/core/Aws.h>
#include <aws/core/auth/AWSCredentials.h>
#include <aws/core/client/ClientConfiguration.h>
#include <aws/core/utils/Outcome.h>
#include <aws/polly/PollyClient.h>
#include <aws/polly/model/SynthesizeSpeechRequest.h>
#include <aws/polly/model/SynthesizeSpeechResult.h>
#include <aws/polly/model/TextType.h>
#include <aws/polly/model/LanguageCode.h>
#include <aws/polly/model/OutputFormat.h>
#include <aws/polly/model/VoiceId.h>
typedef unsigned long DWORD; // 32-bit unsigned integer
typedef unsigned short WORD; // 16-bit unsigned integer
struct riff // Data Bytes Total
{
char chunkID[4]; // "RIFF" 4 4
DWORD riffSize; // file size - 8 4 8
char typeID[4]; // "WAVE" 4 12
char formatChunkID[4]; // "fmt " 4 16
DWORD formatChunkSize; // 16 bytes 4 20
WORD formatTag; // 2 22
WORD noOfChannels; // 2 24
DWORD samplesPerSec; // 4 28
DWORD bytesPerSec; // 4 32
WORD blockAlign; // 2 34
WORD bitsPerSample; // 2 36
char dataChunkID[4]; // "data" 4 40
DWORD dataChunkSize; // not fixed 4 44
};
static struct {
switch_mutex_t *mutex;
switch_thread_rwlock_t *running_rwlock;
switch_memory_pool_t *pool;
int running;
} process;
static struct {
Aws::Auth::AWSCredentials *credentials;
Aws::Client::ClientConfiguration *config;
Aws::SDKOptions *options;
} globals;
switch_loadable_module_interface_t *MODULE_INTERFACE;
static char *supported_formats[SWITCH_MAX_CODECS] = { 0 };
/* Prototypes */
SWITCH_MODULE_LOAD_FUNCTION(mod_polly_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_polly_shutdown);
SWITCH_MODULE_DEFINITION(mod_polly, mod_polly_load, mod_polly_shutdown, NULL);
// ------------------------------------------------------------------------------------------------------------------
/* Implementation */
std::ostream& operator<<(std::ostream& out, const riff& h)
{
if BIG_ENDIAN_SYSTEM {
struct riff hdr = std::move(h);
REVERSE_BYTES(hdr.riffSize);
REVERSE_BYTES(hdr.formatChunkSize);
REVERSE_BYTES(hdr.formatTag);
REVERSE_BYTES(hdr.noOfChannels);
REVERSE_BYTES(hdr.samplesPerSec);
REVERSE_BYTES(hdr.bytesPerSec);
REVERSE_BYTES(hdr.blockAlign);
REVERSE_BYTES(hdr.bitsPerSample);
REVERSE_BYTES(hdr.dataChunkSize);
return out
.write(hdr.chunkID, 4)
.write((const char *)&hdr.riffSize, 4)
.write(hdr.typeID, 4)
.write(hdr.formatChunkID, 4)
.write((const char *)&hdr.formatChunkSize, 4)
.write((const char *)&hdr.formatTag, 2)
.write((const char *)&hdr.noOfChannels, 2)
.write((const char *)&hdr.samplesPerSec, 4)
.write((const char *)&hdr.bytesPerSec, 4)
.write((const char *)&hdr.blockAlign, 2)
.write((const char *)&hdr.bitsPerSample, 2)
.write(hdr.dataChunkID, 4)
.write((const char *)&hdr.dataChunkSize, 4);
} else {
return out
.write(h.chunkID, 4)
.write((const char *)&h.riffSize, 4)
.write(h.typeID, 4)
.write(h.formatChunkID, 4)
.write((const char *)&h.formatChunkSize, 4)
.write((const char *)&h.formatTag, 2)
.write((const char *)&h.noOfChannels, 2)
.write((const char *)&h.samplesPerSec, 4)
.write((const char *)&h.bytesPerSec, 4)
.write((const char *)&h.blockAlign, 2)
.write((const char *)&h.bitsPerSample, 2)
.write(h.dataChunkID, 4)
.write((const char *)&h.dataChunkSize, 4);
}
}
riff init_pcm_header(std::ostream& in)
{
// get length of file
in.seekp(0, in.end);
DWORD sz = in.tellp();
in.seekp(0, in.beg);
struct riff result = {
{'R','I','F','F'}, // chunkID
sz + 0x24, // riffSize (size of stream + 0x24) or (file size - 8)
{'W','A','V','E'}, // typeID
{'f','m','t',' '}, // formatChunkID
16, // formatChunkSize
1, // formatTag (PCM)
1, // noOfChannels (mono)
8000, // samplesPerSec (8KHz)
16000, // bytesPerSec ((Sample Rate * BitsPerSample * Channels) / 8)
2, // blockAlign ((bits per sample * channels) / 8)
16, // bitsPerSample (multiples of 8)
{'d','a','t','a'}, // dataChunkID
sz // dataChunkSize (sample size)
};
return result;
}
struct voice_sync {
char* session_uuid;
Aws::IOStream *audio_stream;
switch_size_t blockAlign;
};
typedef struct voice_sync voice_sync_t;
static switch_status_t polly_file_open(switch_file_handle_t *handle, const char *path)
{
voice_sync_t *sync_info = (voice_sync_t*)malloc(sizeof(voice_sync_t));
sync_info->audio_stream = new Aws::StringStream(std::ios::in | std::ios::out | std::ios::binary);
handle->private_info = sync_info;
handle->samplerate = 8000;
handle->channels = 1;
handle->pos = 0;
handle->format = 0;
handle->sections = 0;
handle->seekable = 0;
handle->speed = 0.5;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "submitting text [%s] to polly", path);
Aws::Polly::PollyClient polly_client(*globals.credentials, *globals.config);
Aws::Polly::Model::SynthesizeSpeechRequest request;
request.SetLanguageCode(Aws::Polly::Model::LanguageCode::en_US);
request.SetOutputFormat(Aws::Polly::Model::OutputFormat::pcm);
request.SetSampleRate("8000");
request.SetTextType(Aws::Polly::Model::TextType::text); // or ssml
request.SetVoiceId(Aws::Polly::Model::VoiceId::Matthew);
request.SetText(path);
if (handle->params) {
// get the session UUID for this channel
// note: this doesnt fire for a standard call session in the audio context; is there a way to make sure it is there?
const char *uuid = switch_event_get_header(handle->params, "session");
if (!zstr(uuid)) {
sync_info->session_uuid = switch_core_strdup(handle->memory_pool, uuid);
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(sync_info->session_uuid), SWITCH_LOG_DEBUG, "Polly linked to session %s\n", sync_info->session_uuid);
}
}
sync_info->audio_stream->clear();
// sync_info->audio_stream.open(filename.c_str(), std::ios::out | std::ios::binary);
auto outcome = polly_client.SynthesizeSpeech(request);
// Output operation status
if (outcome.IsSuccess()) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "received audio response for %s", request.GetServiceRequestName());
Aws::Polly::Model::SynthesizeSpeechResult& result = ((Aws::Polly::Model::SynthesizeSpeechResult&)(outcome));
Aws::IOStream* audio_stream = &result.GetAudioStream();
// this is raw PCM so we need to add a wav header!
riff header = init_pcm_header(*audio_stream);
*sync_info->audio_stream << header;
// tansfer audio data into stream
*sync_info->audio_stream << audio_stream->rdbuf();
sync_info->audio_stream->seekp(0, sync_info->audio_stream->beg);
// update handle information about audio stream
handle->samplerate = header.samplesPerSec;
handle->channels = header.noOfChannels;
handle->format = header.formatTag;
handle->duration = header.dataChunkSize / header.bytesPerSec +1;
handle->samples_in = header.dataChunkSize / header.blockAlign +1;
sync_info->blockAlign = header.blockAlign;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "polly audio stream ready; duration: %ld secs", handle->duration);
return SWITCH_STATUS_SUCCESS;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "something went wrong retrieving audio from polly");
return SWITCH_STATUS_FALSE;
}
static switch_status_t polly_file_close(switch_file_handle_t *handle)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "closiing polly audio stream");
voice_sync_t *sync_info = (voice_sync_t*)handle->private_info;
//sync_info->audio_stream->close(); -- doesnt exist on stringstream
delete sync_info->audio_stream;
if (sync_info->session_uuid) {
switch_safe_free(sync_info->session_uuid);
}
switch_safe_free(sync_info);
handle->private_info = NULL;
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t polly_file_read(switch_file_handle_t *handle, void *data, size_t *len)
{
voice_sync_t *sync_info = (voice_sync_t*)handle->private_info;
switch_size_t bytes;
sync_info->audio_stream->read((char *)data, *len * sync_info->blockAlign);
if ((bytes = sync_info->audio_stream->gcount()) <= 0) {
return SWITCH_STATUS_FALSE;
}
*len = bytes / sync_info->blockAlign;
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_LOAD_FUNCTION(mod_polly_load)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Initializing polly audio interface");
supported_formats[0] = (char*)"polly";
/*
switch_application_interface_t *app_interface;
switch_api_interface_t *api_interface;
*/
switch_file_interface_t *file_interface;
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
file_interface = (switch_file_interface_t*)switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
file_interface->interface_name = modname;
file_interface->extens = supported_formats;
file_interface->file_open = polly_file_open;
file_interface->file_close = polly_file_close;
file_interface->file_read = polly_file_read;
MODULE_INTERFACE = *module_interface;
memset(&process, 0, sizeof(process));
memset(&globals, 0, sizeof(globals));
process.pool = pool;
switch_thread_rwlock_create(&process.running_rwlock, pool);
switch_mutex_init(&process.mutex, SWITCH_MUTEX_NESTED, pool);
globals.options = new Aws::SDKOptions();
globals.options->loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug;
globals.credentials = new Aws::Auth::AWSCredentials();
globals.credentials->SetAWSAccessKeyId("your aws key");
globals.credentials->SetAWSSecretKey("your aws secret");
globals.config = new Aws::Client::ClientConfiguration();
globals.config->region = "eu-west-1"; // Ireland
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Initializing aws api");
Aws::InitAPI(*globals.options);
switch_thread_rwlock_wrlock(process.running_rwlock);
process.running = 1;
switch_thread_rwlock_unlock(process.running_rwlock);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ready to rock!");
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_polly_shutdown)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Shutting down polly polly audio interface");
switch_thread_rwlock_wrlock(process.running_rwlock);
process.running = 0;
switch_thread_rwlock_unlock(process.running_rwlock);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Closing aws api");
Aws::ShutdownAPI(*globals.options);
delete globals.credentials;
delete globals.config;
delete globals.options;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Module shutdown finished");
return SWITCH_STATUS_UNLOAD;
}
Now when i try to load this on Freeswitch , it throws an error
2019-07-31 22:00:51.918181 [CRIT] switch_loadable_module.c:1522 Error Loading module /usr/local/freeswitch/mod/mod_polly.so
/usr/local/freeswitch/mod/mod_polly.so: undefined symbol: _ZNK3Aws35AmazonSerializableWebServiceRequest7GetBodyEv
Freeswitch is C code with C++ guards in header files (extern "C" declaration).
Looking at symbols in mod_polly.so
readelf -Ws mod_polly.so | grep _ZNK3Aws35AmazonSerializableWebServiceRequest7GetBodyEv
66: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZNK3Aws35AmazonSerializableWebServiceRequest7GetBodyEv
590: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZNK3Aws35AmazonSerializableWebServiceRequest7GetBodyEv
Now my basic understanding of the post here tells me that the symbol is present in the so file but Freeswitch cannot find it or load it.
Now this error has very likely to do with mixing C/C++ code but looking at this and this hasn't helped me figure out how to fix it.
I do not want to build Freeswitch to load my module and I am thinking I shouldn't have to, as that renders this project un-scalable.
What am I missing here?
PS:
readelf -Ws libaws-cpp-sdk-core.a | grep AmazonSerializableWebServiceRequest7GetBodyEv
165: 0000000000000000 716 FUNC GLOBAL DEFAULT 42 _ZNK3Aws35AmazonSerializableWebServiceRequest7GetBodyEv
Symbol is defined in libaws-cpp-sdk-core.a which is part of the compilation command for mod_polly.cpp
#Sam V - turns out it was ordering issue while building. Change in ordering of build command to
g++ -shared -o mod_polly.so -fPIC -g -ggdb -std=c++11 -Wall -Werror -I/usr/src/freeswitch/src/include/ -I/usr/src/freeswitch/libs/libteletone/src/ mod_polly.cpp -L/usr/local/lib/ -laws-cpp-sdk-polly -laws-cpp-sdk-core
fixed the problem. Your 1st comment was the key. Thanks.
I'm getting an eror when I include cstdlib in C++.
Unable to open 'malloc.c': File not found (file:///build/glibc-bfm8X4/glibc-2.23/malloc/malloc.c).
The error comes from the top part of the VS code window.
(the error occurs during debugging.)
Here's some of the code:
#include <cstdlib>
#include <portaudio.h>
//...
static int paCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
/* Cast data passed through stream to our structure. */
paTestData *data = (paTestData*)userData;
float *out = (float*)outputBuffer;
unsigned int i;
(void) inputBuffer; /* Prevent unused variable warning. */
for( i=0; i<framesPerBuffer; i++ )
{
*out++ = data->left_phase; /* left */
*out++ = data->right_phase; /* right */
float currentSample = 0;
char *sampleData = new char[4];
for(int j = 0; j < 4; j++)
{
sampleData[j] = currentBuffer[¤tIndex + j];
}
currentSample = (float)atof(sampleData); //cstdlib is included to use atof
//gets audio sample data and forwards to PortAudio
data->left_phase = currentSample;
data->right_phase = currentSample;
currentIndex += 4;
}
return 0;
}
I'm using Linux Mint 81.1 if that helps.
I've fixed this in the follow way ..
my error is
"Unable to open 'libc-start.c': File not found (file:///build/glibc-OTsEL5/glibc-2.27/csu/libc-start.c"
so I make a dir in the root directory
$cd /
$sudo mkdir build
$cd build
$sudo mkdir glibc-OTsEL5
$cd glibc-OTsEL5
and then download the glibc from internet
$sudo wget http://ftp.gnu.org/gnu/glibc/glibc-2.27.tar.gz
then unpack it
$sudo tar -xzvf glibc-2.27.tar.gz
every thing seems to be ok
This solution is taken from https://github.com/microsoft/vscode-cpptools/issues/811#issuecomment-406544778
I encounter the same problem. The problem is that I did not compile the cpp file with debug flag -g.........When I re-compile the cpp file containing malloc and reinterpret_cast, the problem disappeared.
But I am wrong. The true solution is not to step the line that malloc is in, other wise, the source file of malloc.c is needed.
cf, https://github.com/microsoft/vscode-cpptools/issues/811#issuecomment-559085447
) I'm currently developing a project under Qt Creator 4.3.1 which needs an external library to use a key-lock hardware device.
The device comes with a CD with the libraries libkfunc64.so and libkfunc64.a (and the 32 bits versions) presumably compiled for C with gcc. I already tried the libraries in a dummy program to check if they work, and they do.
But when I add the important chunk of code into the Qt project it spits the following error
[...] error: undefined reference to `KFUNC(unsigned int, unsigned int, unsigned int, unsigned int)'
I've already tried to include the library
by coping the libraries to the system directories and simply including the following line in the .pro file
LIBS += -lkfunc64
by using relative paths to the libs in the .pro file
LIBS += -L$$PWD/../build-project/ -lkfunc64
INCLUDEPATH += $$PWD/../build-Qmetrics-Desktop-Debug
DEPENDPATH += $$PWD/../build-Qmetrics-Desktop-Debug
# PRE_TARGETDEPS += $$PWD/../build-Qmetrics-Desktop-Debug/libkfunc64.a
but it keeps showing this error when trying to (re)build it. I've read almost every subject about this issue on the internet but non of them fix this problem.
This is the code for main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QMessageBox>
// Key-lock stuff ----------
#define ValidateCode1 0X488B
#define ValidateCode2 0XFEE2
#define ValidateCode3 0XEF90
#define ClientIDCode1 0xB862
#define ClientIDCode2 0x54CB
#define ReadCode1 0X1772
#define ReadCode2 0XC4E6
#define ReadCode3 0XBCF8
extern unsigned long KFUNC(unsigned, unsigned, unsigned, unsigned);
unsigned RotateLeft(unsigned, int);
void KTASK(unsigned, unsigned, unsigned, unsigned);
unsigned short ReturnValue1, ReturnValue2;
// -------------------------
int main(int argc, char *argv[])
{
KTASK(1, ValidateCode1, ValidateCode2, ValidateCode3);
KTASK(RotateLeft(ReturnValue1, ReturnValue2 & 7) ^ ReadCode3 ^ ReturnValue2, RotateLeft(ReturnValue2, ReturnValue1 & 15), ReturnValue1 ^ ReturnValue2, 0);
if ((ReturnValue1 == ClientIDCode1) && (ReturnValue2 == ClientIDCode2))
{
QApplication app(argc, argv);
MainWindow w;
w.showFullScreen();
return app.exec();
}
else
{
QMessageBox msgBox;
msgBox.setText("Wrong or missing key-lock!");
return msgBox.exec();
}
}
unsigned RotateLeft(unsigned Target, int Counts)
{
int i;
static unsigned LocalTarget, HighBit;
LocalTarget = Target;
for (i=0; i<Counts; i++)
{
HighBit = LocalTarget & 0X8000;
LocalTarget = (LocalTarget << 1) + (HighBit >> 15);
}
LocalTarget = LocalTarget & 0XFFFF; /* For 32 bit integers */
return (LocalTarget);
}
void KTASK(unsigned CommandCode, unsigned Argument2, unsigned Argument3, unsigned Argument4)
{
unsigned long int ReturnValue;
ReturnValue = KFUNC(CommandCode, Argument2, Argument3, Argument4); // <--- this is the only function that is used from the external library
ReturnValue1 = (unsigned) (ReturnValue & 0XFFFF);
ReturnValue2 = (unsigned) (ReturnValue >> 16);
}
And the (relevant part of the) .pro file is as follow
# Adds OpenCV, DC1394 and Keylok libraries
unix {
CONFIG += link_pkgconfig
PKGCONFIG += opencv
LIBS += -ldc1394 -lkfunc64
}
I really don't know what to do :'(
Have you tried declaring the function with extern "C"?
e.G.:
#ifdef __cplusplus
extern "C"
{
#endif
extern unsigned long KFUNC(unsigned, unsigned, unsigned, unsigned);
#ifdef __cplusplus
};
#endif
This is nessecary to call a external c function from c++.
I'm on working on someone's else code which is written for some socket programming. This project has following two files.
SOCKUTIL.H
#if !defined(SOCKUTIL_H)
#define SOCKUTIL_H
unsigned long inet_addr(const char *sIp);
unsigned short htons(unsigned short port);
#endif
sockUtil.cpp
#include "stdafx.h"
#include "sockutil.h"
#include <stdlib.h>
#include <string.h>
unsigned long inet_addr(const char *sIp)
{
int octets[4];
int i;
const char *auxCad = sIp;
unsigned long lIp = 0;
//we extract each octet of the ip address
//atoi will get characters until it found a non numeric character(in our case '.')
for(i = 0; i < 4; i++)
{
octets[i] = atoi(auxCad);
if(octets[i] < 0 || octets[i] > 255)
{
return(0);
}
lIp |= (octets[i] << (i * 8));
//update auxCad to point to the next octet
auxCad = strchr(auxCad, '.');
if(auxCad == NULL && i != 3)
{
return(0);
}
auxCad++;
}
return(lIp);
}
unsigned short htons(unsigned short port)
{
unsigned short portRet;
portRet = ((port << 8) | (port >> 8));
return(portRet);
}
This project originally was developed in VC6 and when I opened it in VS2013, Visual studio converted it. But when I build it, then it is giving following errors.
error C2373: 'inet_addr' : redefinition; different type modifiers
error C2373: 'htons' : redefinition; different type modifiers
I tried to find solution, but didn't get what to do. I don't have much knowledge on it.
Edit: This code doesn't use #include Winsock2.h. I checked few online solutions available which claims that this library is the reason for redefinition but this is not true in this case.
These functions are already defined for you in more recent versions of Visual Studio (see: MSDN) - you can just remove these files from your project and remove all occurrences of:
#include "sockutil.h"
I am trying to write code for my atmega328 in C++ using Eclipse CDT. I have two projects. One project is static library project, that produces a static library. All the files in library are compiled without errors and library is created using the following command:
avr-ar -r "libRobotMainBoard.a" ./Console.o ./Motor.o ./RingBuffer.o ./io.o ./operators.o
c:\Program Files\WINAVR\bin\avr-ar.exe: creating libRobotMainBoard.a
Then I use this library in other project that produces hex file for my atmega. But during the linking I get error:
C:\Users\Mitch\Disk Google\workspace\AVR\RobotMainBoard\Release\libRobotMainBoard.a(Console.o): In function Console::putCharToUDR()':
Console.cpp:(.text._ZN7Console12putCharToUDREv+0x2): undefined reference to Console::txBuff'
and many othert similar to this. I have tried to find the solution on the web. Most of them mentions that this error is caused by naming library and the compiled file in the wrong order. I checked that and my order should be fine. I am linking it with the command:
avr-g++ -Wl,-Map,BoardTest.map,--cref -mrelax -Wl,--gc-sections -L"C:\Users\Mitch\Disk Google\workspace\AVR\RobotMainBoard\Release" -mmcu=atmega328p -o "BoardTest.elf" ./main.o -lRobotMainBoard
The main.cpp file looks like this:
#include <util/delay.h>
#include "Console.h"
#include "Motor.h"
Motor leftMotor(9,7);
Motor rightMotor(10,8);
int main(){
leftMotor.stop();
rightMotor.stop();
Console::setup(250000);
while(1){
Console::send('a');
_delay_ms(2000);
}
}
When I comment the Console lines out, it will link OK, even with Motor lines, which source files are in the same lib.
The Console cpp file is like this:
#include <avr/interrupt.h>
#include "Console.h"
#include "operators.h"
void Console::setup(uint16_t baudrate) {
rxBuff = new RingBuffer(RX_BUFF_SIZE);
txBuff = new RingBuffer(TX_BUFF_SIZE);
uint16_t baudPrescaler= (F_CPU / (baudrate * 16)) - 1;
UCSR0A = 0x00; UCSR0B = 0x00; UCSR0C = 0x00;
//Using 8-bit, asynchronous, normal speed, 1 stop bit, no parity check
UBRR0 = baudPrescaler;
UCSR0C |= (1 << UCSZ01) | (1 << UCSZ00); //8-bit
UCSR0B |= (1 << TXEN0) | (1 << RXEN0);
sei();
}
void Console::send(char c) {
txBuff->add(c);
UCSR0B |= (1 << UDRIE0);
}
void Console::send(const char* s) {
while(*s){
send(*s++);
}
}
void Console::putCharToUDR(){
if(!txBuff->empty()){
UDR0 = txBuff->remove();
} else {
UCSR0B &= ~(1 << UDRIE0);
}
}
uint8_t Console::canReceive() {
return rxBuff->available();
}
uint8_t Console::canTransmit() {
return txBuff->available();
}
ISR(USART_RX_vect, ISR_BLOCK){
}
ISR(USART_UDRE_vect, ISR_BLOCK){
Console::putCharToUDR();
}
Do anybody of you have any idea, why I am still getting the linking error?
EDIT 1
#ifndef CONSOLE_H_
#define CONSOLE_H_
#include "RingBuffer.h"
#define RX_BUFF_SIZE 32
#define TX_BUFF_SIZE 32
class Console {
public:
static void setup(uint16_t baudrate);
static void send(char c);
static void send(const char* s);
static uint8_t canReceive();
static uint8_t canTransmit();
static void putCharToUDR();
private:
static RingBuffer *rxBuff;
static RingBuffer *txBuff;
};
#endif /* CONSOLE_H_ */
As txBuff is static, you have to provide its definition in Console.cpp, e.g.
RingBuffer * Console::txBuff = new RingBuffer(RX_BUFF_SIZE);