I'm trying to build a c++ project in VS Code but when i try to build it g++ throws an error saying:
g++ -std=c++17 -ggdb -Iinclude src/main.cpp -o bin/main
Undefined symbols for architecture x86_64:
"MessageBus::MessageBus()", referenced from:
_main in main-244f95.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [bin/main] Error 1
The terminal process "/bin/zsh '-c', 'make'" terminated with exit code: 2.
Here are the files that i think are causing the problem:
MessageBus.h
#pragma once
#include "../Utils/Queue.h"
#include "../Utils/SimpleList.h"
#include "Messages/Message.h"
class System;
class MessageBus
{
public:
MessageBus();
~MessageBus();
void addReciever(System* system);
void postMessage(Message* msg);
void notify();
private:
Queue<Message> msgQueue;
SimpleList<System*> systems;
};
MessageBus.cpp
#include "MessageBus.h"
#include "System.h"
MessageBus::MessageBus() {}
MessageBus::~MessageBus() {}
void MessageBus::postMessage(Message* msg) {
msgQueue.add(msg);
}
void MessageBus::addReciever(System* system) {
systems.add(system);
}
void MessageBus::notify() {
int queueLength = msgQueue.getLength();
for (int i = 0; i < queueLength; i++) {
Message msg = msgQueue.pop();
for (int j = 0; j < systems.getLength(); j++) {
System* system = systems.get(j);
system->handleMessage(&msg);
}
}
}
main.cpp
#include "EventSystem/MessageBus.h"
int main(int argc, char* argv[])
{
MessageBus* msgBus = new MessageBus();
}
Makefile
CXX := g++
CXX_FLAGS := -std=c++17 -ggdb
BIN := bin
SRC := src
INCLUDE := include
LIBRARIES :=
EXECUTABLE := main
all: $(BIN)/$(EXECUTABLE)
run: clean all
clear
./$(BIN)/$(EXECUTABLE)
$(BIN)/$(EXECUTABLE): $(SRC)/*.cpp
$(CXX) $(CXX_FLAGS) -I$(INCLUDE) $^ -o $# $(LIBRARIES)
clean:
-rm $(BIN)/*
But when i try to compile these files together using the terminal:
g++ main.cpp EventSystem/MessageBus.cpp -o maintest
it works just fine, so i think the problem is that my files aren't compiled together. I think this might have something to do with the linker being unable to find the correct files and it might have something to do with my project structure?
This is my current structure
As you can see the header files are located together with the source code. Should i separate the header files from the cpp files or is it that i have put them in subdirectories? Or is it something else entirely? I'm somewhat new to c++ and Makefiles and i can't seem to understand what is causing the problem.
Edit:
Solution:
As #MadScientist suggested i replaced $(SRC)/*.cpp in my Makefile with $(shell find $(SRC) -name \*.cpp -print) which solved the problem. But as #WhozCraig mentioned i should probably switch to cmake to avoid Makefiles in the future.
You list the "working" command as:
g++ main.cpp EventSystem/MessageBus.cpp -o maintest
but your recipe is:
$(BIN)/$(EXECUTABLE): $(SRC)/*.cpp
The glob expression $(SRC)/*.cpp won't match the file main.cpp.
If we could see your link line, we'd probably be able to see that main.cpp is missing.
I tried to compile my c++ class with sqltie3 include.
I run Ubuntu 20.04.
For this I use the i686-w64-mingw32-g++ cross compiler, I also tested it with g++ and it works perfectly but not with the i686-w64-mingw32-g++ compiler.
I always get the same error:
/usr/bin/i686-w64-mingw32-ld: DBWrapper.o:DBWrapper.cpp:(.text+0x61): undefined reference to `sqlite3_open'
/usr/bin/i686-w64-mingw32-ld: DBWrapper.o:DBWrapper.cpp:(.text+0x12c): undefined reference to `sqlite3_close'
My Makefile:
mingw = i686-w64-mingw32-g++
SQLCOMPILE = -I/usr/local/sqlite/include
CFLAGS = -Wall
SRCFILES = *.cpp
OBJFILES = *.o
TARGETWIN = progwx.exe
all: $(TARGETWIN)
$(TARGETWIN): $(OBJFILES)
$(mingw) $(CFLAGS) $(OBJFILES) $(SQLCOMPILE) -o $(TARGET) -l sqlite3
$(OBJFILES): $(SRCFILES)
$(mingw) $(CFLAGS) $(SQLCOMPILE) -c $(SRCFILES)
.PHONY: clean
clean:
rm -f *.o
I put the sqlite source code in $(SQLCOMPILE) and the compiler can include everything unless I call the sqlite3_open() function.
I also compiled the source code to a library (libsqlite3.a) so that the -l tag can find it.
Because the g++ compiler brings also the same "undefined reference" error if I don't put the -lsqlite3 tag in.
$ i686-w64-mingw32-gcc -c sqlite3.c
$ ar rcs libsqlite3.a sqlite3.o
Here is my Headerfile (DBWrapper.h):
#pragma once
#include <string>
#include <stdexcept>
#include <sqlite3.h>
class DBWrapper {
sqlite3 *db_;
const int errCode;
public:
DBWrapper(const std::string &dbname);
DBWrapper(const DBWrapper&) = delete;
DBWrapper& operator=(const DBWrapper&) = delete;
sqlite3* operator*();
~DBWrapper();
};
Here is my CPP-File (DBWrapper.cpp):
#include "DBWrapper.h"
DBWrapper::DBWrapper(const std::string &dbname) : db_(nullptr), errCode(sqlite3_open(dbname.c_str(), &db_)){
if(errCode) {
throw std::runtime_error("ERROR at opening database!");
}
}
DBWrapper::~DBWrapper() {
sqlite3_close(db_);
}
sqlite3* DBWrapper::operator *() {
return db_;
}
(sorry for my bad english)
I figured it out I just needed sqlite3 as a compiled object file (sqlite3.o) for the compiler.
I am having trouble building standalone webassembly with the full control I want over memory and layout. I don't want to use emscripten because, as the following post says, it doesn't give me all of the compile-time options I want (e.g. stack size control, being able to choose to import memory in standalone mode, etc.) I've been folowing pages such as: How to generate standalone webassembly with emscripten
Also, emscripten is overkill.
What I've done so far:
I have a fully working llvm 9 toolchain downloaded via homebrew (I am on macos 10.14.)
I was following a mix of https://aransentin.github.io/cwasm/ and https://depth-first.com/articles/2019/10/16/compiling-c-to-webassembly-and-running-it-without-emscripten/
I used wasi to get the C standard library. Using linker flags like -Wl,-z,stack-size=$[1024 * 1024] I could control the stack size. Compilation was successful. Great!
However, I need to use C++ standard libraries to support some of my own and other third party libraries.
As far as I can tell, there doesn't seem to be any easy way to get libc++ and libc++abi.
I tried a "hack" in which I downloaded Emscripten and had it build its own libc++ and libc++abi files. Then I tried copying those files and headers into the right spot.
Then I got error messages referring to a missing threading API, which apparently were caused by not compiling with EMSCRIPTEN. So I defined the EMSCRIPTEN macro and that sort of worked. Then I thought that maybe I could remove the wasi dependency and use emscripten's version of libc to be consistent, but then there were conflicting / missing headers too.
In short, I think I got somewhat close to where I needed to be, but things just got terribly messy. I doubt I took the simplest non-emscripten approach.
Has anyone successfully created a build system for standalone webassembly that lets you use the c and c++ standard libraries?
EDIT:
This is the super hacky build script I have now (it's a heavily modified version of something I found online):
DEPS =
OBJ = library.o
STDLIBC_OBJ = $(patsubst %.cpp,%.o,$(wildcard stdlibc/*.cpp))
OUTPUT = library.wasm
DIR := ${CURDIR}
COMPILE_FLAGS = -Wall \
--target=wasm32-unknown-wasi \
-Os \
-D __EMSCRIPTEN__ \
-D _LIBCPP_HAS_NO_THREADS \
-flto \
--sysroot ./ \
-std=c++17 \
-ffunction-sections \
-fdata-sections \
-I./libcxx/ \
-I./libcxx/support/xlocale \
-I./libc/include \
-DPRINTF_DISABLE_SUPPORT_FLOAT=1 \
-DPRINTF_DISABLE_SUPPORT_LONG_LONG=1 \
-DPRINTF_DISABLE_SUPPORT_PTRDIFF_T=1
$(OUTPUT): $(OBJ) $(NANOLIBC_OBJ) Makefile
wasm-ld \
-o $(OUTPUT) \
--no-entry \
--export-all \
--initial-memory=131072 \
--stack-size=$[1024 * 1024] \
-error-limit=0 \
--lto-O3 \
-O3 \
-lc -lc++ -lc++abi \
--gc-sections \
-allow-undefined-file ./stdlibc/wasm.syms \
$(OBJ) \
$(LIBCXX_OBJ) \
$(STDLIBC_OBJ)
%.o: %.cpp $(DEPS) Makefile
clang++ \
-c \
$(COMPILE_FLAGS) \
-fno-exceptions \
-o $# \
$<
library.wat: $(OUTPUT) Makefile
~/build/wabt/wasm2wat -o library.wat $(OUTPUT)
wat: library.wat
clean:
rm -f $(OBJ) $(STDLIBC_OBJ) $(OUTPUT) library.wat
I dropped-in libc, libc++, and libc++abi from emscripten (but honestly this is a terrible installation process.)
I've been incrementally trying to fill in gaps that I guess emscripten would've normally done, but now I'm stuck again:
./libcxx/type_traits:4837:57: error: use of undeclared identifier 'byte'
constexpr typename enable_if<is_integral_v<_Integer>, byte>::type &
^
./libcxx/type_traits:4837:64: error: definition or redeclaration of 'type'
cannot name the global scope
constexpr typename enable_if<is_integral_v<_Integer>, byte>::type &
I am no longer sure if this will even work since the system might accidentally compile something platform-specific in. Really what I'd like is a shim that would just let me use the standard containers mostly.
This has become kind of unmanageable. What might I do next?
EDIT 2: Right so that's missing C++17 type trait content, and when I go to C++14 (I still want C++17) I end up with more missing things.
Definitely stuck.
EDIT 3:
I sort of started over. The libraries are linking, and I'm able to use the standard, but I'm seeing errors like the following if I try to use e.g. an std::chrono's methods (I can instantiate the object):
wasm-ld: error: /var/folders/9k/zvv02vlj007cc0pm73769y500000gn/T/library-4ff1b5.o: undefined symbol: std::__1::chrono::system_clock::now()
I'm currently using the static library abi from emscripten and the static library C++ standard library from my homebrew installation of llvm (I tried the emscripten one but that didn't work either).
I'm not really sure if this is related to name mangling. I'm currently exporting all symbols from webasm so malloc and co. get exported as well.
Here is my build script:
clang++ \
--target=wasm32-unknown-wasi \
--std=c++11 \
-stdlib=libc++ \
-O3 \
-flto \
-fno-exceptions \
-D WASM_BUILD \
-D _LIBCPP_HAS_NO_THREADS \
--sysroot /usr/local/opt/wasi-libc \
-I/usr/local/opt/wasi-libc/include \
-I/usr/local/opt/glm/include \
-I./libcxx/ \
-L./ \
-lc++ \
-lc++abi \
-nostartfiles \
-Wl,-allow-undefined-file wasm.syms \
-Wl,--import-memory \
-Wl,--no-entry \
-Wl,--export-all \
-Wl,--lto-O3 \
-Wl,-lc++, \
-Wl,-lc++abi, \
-Wl,-z,stack-size=$[1024 * 1024] \
-o library.wasm \
library.cpp
My code:
#include "common_header.h"
#include <glm/glm.hpp>
#include <unordered_map>
#include <vector>
#include <string>
#include <chrono>
template <typename T>
struct BLA {
T x;
};
template <typename T>
BLA<T> make_BLA() {
BLA<T> bla;
std::unordered_map<T, T> map;
std::vector<T> bla2;
std::string str = "WEE";
//str = str.substr(0, 2);
return bla;
}
#ifdef __cplusplus
extern "C" {
#endif
char* malloc_copy(char* input)
{
usize len = strlen(input) + 1;
char* result = (char*)malloc(len);
if (result == NULL) {
return NULL;
}
strncpy(result, input, len);
return result;
}
void malloc_free(char* input)
{
free(input);
}
float32 print_num(float val);
float32 my_sin(float32 val)
{
float32 result = sinf(val);
float32 result_times_2 = print_num(result);
print_num(result_times_2);
return result;
}
long fibonacci(unsigned n) {
if (n < 2) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
void set_char(char* input)
{
input[0] = '\'';
uint8 fibonacci_series[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };
for (uint8 number : fibonacci_series) {
input[0] = number;
}
auto WEE = make_BLA<int>();
WEE.x = 18;
glm::vec4 v(100.0f, 200.0f, 300.0f, 1.0f);
glm::vec4 v_out = glm::mat4(1.0f) * v;
input[0] = 5 + static_cast<int>(v_out.x) * input[1];
auto start = std::chrono::system_clock::now();
long out = fibonacci(42);
auto end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
auto elapsed = elapsed_seconds.count();
}
#ifdef __cplusplus
}
#endif
When I tried exporting dynamically with the "visible" attribute on only the functions that had no C++, the project compiled, but the wasm module failed to load in JavaScript, so I think the problem was still there.
This is as far as I've gotten. Might the issue be related to the fact that I'm using a different compiler from the one used to create the static libraries? (I'm using homebrew clang 9). Hopefully not. I'd be kind of stuck then because I couldn't find another way to get the libraries. Manual llvm compilation seemed to fail.
The excellent wasi-sdk pulls upstream llvm-project (which provides clang++) and wasi-libc as git submodules and compiles them using suitable flags (most notably disabling pthreads which is not yet supported in wasi-libc).
You can then compile your own C++ source using the following minimal set of options:
/path/to/wasi-sdk/build/install/opt/wasi-sdk/bin/clang++ \
-nostartfiles \
-fno-exceptions \
-Wl,--no-entry \
-Wl,--strip-all \
-Wl,--export-dynamic \
-Wl,--import-memory \
-fvisibility=hidden \
--sysroot /path/to/wasi-sdk/build/install/opt/wasi-sdk/share/wasi-sysroot \
-o out.wasm \
source.cpp
If you want to import functions from the runtime, I would suggest adding an additional line:
-Wl,--allow-undefined-file=wasm-import.syms \
You then can put function names separated by newlines into wasm-import.syms so that the linker won't complain about undefined functions.
Note that all this is completely independent of Emscripten.
I'm having issues when compiling/Linking with LTO enabled with GCC 4.8.1. I get undefined references to symbols in a DLL even though they seem to be present. The strange thing is, without LTO enabled it compiles and links successfully. LTO seems to struggle when there is a virtual destructor that hasn't been defined in the derived class.
Removing the DECLSPEC makes it compile and work with LTO enabled.
Dependency walker shows the symbols are there. The link time optimizer just can't seem to find them.
Declaring any type of destructor in derived class Test makes it work.
Removing LTO optimization also makes it work successfully, I'm wondering why this is an issue.
Test is a shared library, Main links to the shared library.
Test.h
#include <string>
#ifdef SOURCE
#define DECL __declspec(dllexport)
#warning Exporting!
#else
#define DECL __declspec(dllimport)
#warning Importing!
#endif
class DECL TestBase
{
public:
TestBase(const std::string testing);
virtual ~TestBase();
std::string getTesting();
private:
std::string _testing;
};
class DECL Test : public TestBase
{
public:
Test(const std::string testing);
//~Test(); //removing causes a linker error with LTO! Fine without LTO.
};
Test.cpp
#include "Test.h"
TestBase::TestBase(const std::string testing)
{
_testing = testing;
}
TestBase::~TestBase()
{
}
std::string TestBase::getTesting()
{
return _testing;
}
Test::Test(const std::string testing) :
TestBase(testing)
{
}
/*Test::~Test() //removing causes a linker error with LTO! Fine without LTO.
{
}*/
Main.cpp
#include "Test.h"
#include <iostream>
int main()
{
Test test("testing!");
std::cout << test.getTesting() << std::endl;
return 0;
}
Excuse my messy makefile..
CC=g++
LD=g++
LIBCFLAGS= -O3 -march=pentium4 -mfpmath=sse -flto -fuse-linker-plugin
LIBEXTRA= -c -DSOURCE
LIBLDFLAGS= ${LIBCFLAGS} -shared
LIBSOURCES=Test.cpp
LIBRARY=Test.dll
EXECFLAGS= -O3 -march=pentium4 -mfpmath=sse -flto -fuse-linker-plugin
EXTRA= -c
EXELDFLAGS= ${EXECFLAGS} -L. -lTest
SOURCES=Main.cpp
EXECUTABLE=main
LIBOBJECTS=$(LIBSOURCES:.cpp=.o)
OBJECTS=$(SOURCES:.cpp=.o)
all: $(SOURCES) $(LIBRARY) $(EXECUTABLE)
$(LIBRARY): $(LIBOBJECTS)
$(LD) $(LIBLDFLAGS) $(LIBOBJECTS) -o $#
$(EXECUTABLE): $(OBJECTS)
$(LD) $(EXELDFLAGS) $(OBJECTS) -o $#
$(OBJECTS): CFLAGS := $(EXECFLAGS) $(EXTRA)
$(LIBOBJECTS): CFLAGS := $(LIBCFLAGS) $(LIBEXTRA)
.cpp.o:
#echo "... Making: $#"
$(CC) $(CFLAGS) $< -o $#
clean:
- del /f /q *.o
- del /f /q *.dll
- del /f /q *.exe
I'm working on a simulation in Qt (C++), and would like to make use of a Semaphore wrapper class I made for the sem_t type.
Although I am including semaphore.h in my wrapper class, running qmake provides the following error:
'sem_t does not name a type'
I believe this is a library/linking error, since I can compile the class without problems from the command line.
I've read that you can specify external libraries to include during compilation. However, I'm a) not sure how to do this in the project file, and b) not sure which library to include in order to access semaphore.h.
Any help would be greatly appreciated.
Thanks,
Tom
Here's the wrapper class for reference:
Semaphore.h
#ifndef SEMAPHORE_H
#define SEMAPHORE_H
#include <semaphore.h>
class Semaphore {
public:
Semaphore(int initialValue = 1);
int getValue();
void wait();
void post();
private:
sem_t mSemaphore;
};
#endif
Semaphore.cpp
#include "Semaphore.h"
Semaphore::Semaphore(int initialValue) {
sem_init(&mSemaphore, 0, initialValue);
}
int Semaphore::getValue() {
int value;
sem_getvalue(&mSemaphore, &value);
return value;
}
void Semaphore::wait() {
sem_wait(&mSemaphore);
}
void Semaphore::post() {
sem_post(&mSemaphore);
}
And, the QT Project File:
TARGET = RestaurantSimulation
TEMPLATE = app
QT +=
SOURCES += main.cpp \
RestaurantGUI.cpp \
RestaurantSetup.cpp \
WidgetManager.cpp \
RestaurantView.cpp \
Table.cpp \
GUIFood.cpp \
GUIItem.cpp \
GUICustomer.cpp \
GUIWaiter.cpp \
Semaphore.cpp
HEADERS += RestaurantGUI.h \
RestaurantSetup.h \
WidgetManager.h \
RestaurantView.h \
Table.h \
GUIFood.h \
GUIItem.h \
GUICustomer.h \
GUIWaiter.h \
Semaphore.h
FORMS += RestaurantSetup.ui
LIBS +=
Full Compiler Output:
g++ -c -pipe -g -gdwarf-2 -arch i386 -Wall -W -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -
I/usr/local/Qt4.6/mkspecs/macx-g++ -I. -
I/Library/Frameworks/QtCore.framework/Versions/4/Headers -I/usr/include/QtCore -
I/Library/Frameworks/QtGui.framework/Versions/4/Headers -I/usr/include/QtGui -
I/usr/include -I. -I. -F/Library/Frameworks -o main.o main.cpp
In file included from RestaurantGUI.h:10,
from main.cpp:2:
Semaphore.h:14: error: 'sem_t' does not name a type
make: *** [main.o] Error 1
make: Leaving directory `/Users/thauburger/Desktop/RestaurantSimulation'
Exited with code 2.
Error while building project RestaurantSimulation
When executing build step 'Make'
I was able to compile and link your semaphore class using qmake without any unexpected steps (including linking in the rt or pthread libraries). I created the following main:
#include "Semaphore.h"
int main(int argc, char* argv[])
{
Semaphore sem;
return 0;
}
And then I generated the following project file using qmake -project:
######################################################################
# Automatically generated by qmake (2.01a) Mon May 24 12:50:02 2010
######################################################################
TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .
# Input
HEADERS += Semaphore.h
SOURCES += main.cpp Semaphore.cpp
Whatever error you're seeing is caused by something other than your Semaphore class. I'd recommend taking a good look at your RestaurantGUI.h file. You may need to take a look at the preprocessed output (gcc's -E flag) in order to see what's really happening.
NOTE: I'd recommend renaming your semaphore files to something that will work on case-insensitive filesystems, such as Windows.
Why don't you use semaphore mechanism provided by the Qt framework? I'd use QSemaphores just to stay within Qt ecosystem.
QMake adds external include path using INCLUDEPATH
like INCLUDEPATH += include_dir
What is your INCLUDEPATH set to in the pro file?