I'm trying to build these files but it's giving me a multiple definition error.
main.cpp:
#include "SDL/SDL.h"
#include "Core.h"
#include "GameStates.h"
#include "globals.h"
int main(int argc, char** args)
{
if(core.Initilization(640, 480, 32, SDL_SWSURFACE) == -1)
{
SDL_Quit();
}
while(core.desiredstate != core.quit)
{
::currentstate->EventHandling();
::currentstate->Logic();
core.ChangeState();
::currentstate->Render();
::currentstate->Update();
}
SDL_FreeSurface(core.screen);
SDL_Quit();
}
Core.cpp:
#include "Core.h"
#include "GameStates.h"
#include "SDL/SDL.h"
#include "Intro.h"
#include "globals.h"
#include <string>
/* Starts SDL subsystems and sets screen attributes */
bool Core::Initilization(int SCREEN_WIDTH, int SCREEN_HEIGHT, int SCREEN_BPP, int FLAGS)
{
//starts SDL subsystems, returns false upon error
if(SDL_Init(SDL_INIT_EVERYTHING) == -1)
{
return false;
}
//The screen
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, FLAGS);
//Returns false if there was an error
if(screen == NULL)
{
return false;
}
SDL_WM_SetCaption("Game", NULL);
return true;
}
/* Loads an image and optimizes it */
SDL_Surface* Core::Load(std::string filename)
{
//original loaded image
SDL_Surface* original = SDL_LoadBMP(filename.c_str());
SDL_Surface* optimized = NULL;
if(original != NULL)
{
//Sets optimized to optimized version of original
optimized = SDL_DisplayFormat(original);
SDL_FreeSurface(original);
}
return optimized;
}
/* Blits surfaces */
void Core::ApplySurface(int x, int y, SDL_Surface* source, SDL_Surface* destination)
{
//holds the x y coordinates
SDL_Rect location;
location.x = x;
location.y = y;
if(destination != NULL)
{
SDL_BlitSurface(source, NULL, destination, &location);
}
}
/* Sets desiredstate to be used in ChangeState(); */
void Core::SetState(int newstate)
{
if(desiredstate != state_null && desiredstate != quit)
{
desiredstate = newstate;
}
}
/* Changes the game state */
void Core::ChangeState()
{
if(desiredstate != state_null && desiredstate != quit)
{
//frees old state memory
delete ::currentstate;
switch(desiredstate)
{
case intro:
//allocates new state memory
::currentstate = new Intro();
break;
}
stateID = desiredstate;
desiredstate = state_null;
}
}
GameStates.h:
#ifndef GAMESTATES_H
#define GAMESTATES_H
class GameStates
{
public:
virtual void EventHandling() = 0;
virtual void Logic() = 0;
virtual void Render() = 0;
virtual void Update() = 0;
};
#endif
Intro.h:
#ifndef INTRO_H
#define INTRO_H
#include "SDL/SDL.h"
#include "GameStates.h"
class Intro : public GameStates
{
private:
SDL_Surface* test;
public:
Intro();
void EventHandling();
void Logic();
void Render();
void Update();
~Intro();
} intro;
#endif
Intro.cpp:
#include "Intro.h"
#include "GameStates.h"
#include "Core.h"
#include "SDL/SDL.h"
Intro::Intro()
{
test = core.Load("test.bmp");
}
void Intro::EventHandling()
{
SDL_Event event;
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT:
core.SetState(core.quit);
break;
}
}
}
void Intro::Logic()
{
//to be coded when the program actually builds...
}
void Intro::Render()
{
core.ApplySurface(30, 30, test, core.screen);
}
void Intro::Update()
{
SDL_Flip(core.screen);
}
Intro::~Intro()
{
SDL_FreeSurface(test);
}
globals.h:
#include "GameStates.h"
#include "SDL/SDL.h"
GameStates* currentstate = NULL;
Sorry if the indentation is off; having to put four spaces for it to be seen as a code block messed with it a bit.
Heres the error message:
/tmp/ccWxKsO5.o:(.bss+0x0): multiple definition of `core'
/tmp/cc13Eqmt.o:(.bss+0x0): first defined here
/tmp/ccWxKsO5.o:(.bss+0x20): multiple definition of `currentstate'
/tmp/cc13Eqmt.o:(.bss+0x10): first defined here
/tmp/ccJXxewI.o:(.bss+0x0): multiple definition of `intro'
/tmp/ccWxKsO5.o:(.bss+0x10): first defined here
/tmp/ccJXxewI.o:(.bss+0x10): multiple definition of `core'
/tmp/cc13Eqmt.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status
Makefile:
OBJS = main.o Intro.o Core.o
CC = g++
DEBUG = -g
CFLAGS = -Wall -c $(DEBUG)
LIBS = -lSDL
game : $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o game $(LIBS)
main.o : Core.h GameStates.h globals.h
$(CC) $(CFLAGS) main.cpp $(LIBS)
Core.o : Core.h Core.cpp GameStates.h Intro.h globals.h
$(CC) $(CFLAGS) Core.cpp $(LIBS)
Intro.o : Intro.cpp GameStates.h Core.h
$(CC) $(CFLAGS) Intro.cpp $(LIBS)
The problem isn't your code, it's your build system.
Any sane build system matches the name of the object files to the name of the source files. But you have ccWxKsO5.o and cc13Eqmt.o. What's worse, the build system appears to be trying to link multiple objects generated from the same source (perhaps some were created by an earlier run of the compiler).
tempnam and globbing *.o is not a reasonable way to build C++ programs.
Well, there may be some code problems also. But those will be a thousand times easier to find and fix once the object names in the error messages correlate to source files.
For objects shared between multiple translation units, the rule is: there must be exactly one definition, but you may have multiple declarations.
In practice, this means: put "extern Class object;" in your .h file, and "Class object;" in exactly one of your .CPP files.
For intro, for example, change your Intro.h to:
class Intro : public GameStates
{
... // whatever
};
extern Intro intro;
and add this line to Intro.cpp:
Intro intro;
Similarly for currentstate, in globals.h:
extern GameStates* currentstate;
and in one .CPP (it doesn't matter to the compiler which one):
GateStates* currentstate = NULL;
P.s. Your makefile is broken. You pass -c, which means "don't link" to your link step. Try this:
OBJS = main.o Intro.o Core.o
CC = g++
DEBUG = -g
CFLAGS = -Wall $(DEBUG)
LIBS = -lSDL
game : $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o game $(LIBS)
main.o : Core.h GameStates.h globals.h
$(CC) -c $(CFLAGS) main.cpp
Core.o : Core.h Core.cpp GameStates.h Intro.h globals.h
$(CC) -c $(CFLAGS) Core.cpp
Intro.o : Intro.cpp GameStates.h Core.h
$(CC) -c $(CFLAGS) Intro.cpp
In globals.h, you must declare currentstate extern. Then create globals.cpp, with the definition (GameStates* currentstate = NULL;). I couldn't find any reference for intro or core in your code, but it's probably the same problem: you can declare global variables as often as you want as long as you declare them extern, and only define them once per resulting binary, in only one translation unit.
Also, you probably want to add a header guard (#ifndef GLOBALS_H ...) to globals.h, just in case you add anything else in there.
put include guards in globals.h
make GameStates* declaration extern
//globals.h
#ifndef _MY_GLOBALS_H_
#define _MY_GLOBALS_H_
#include "GameStates.h"
#include "SDL/SDL.h"
extern GameStates* currentstate;
#endif
//Main.cpp
#include "globals.h"
GameStates* currentState = 0;
Related
Im working on making a simulator with c++, for which I need to read files.
my directory looks something like this
proj
------>bin #stores the executable
------>include #stroes the external library includefiles
------>lib #stores the lib files of the libraries
------>obj #stores the .o files
------>src #source files
makefile
my make file looks this
CC = g++
OUT = chip8
ODIR = ./obj
SDIR = ./src
OUTDIR = ./bin
IDIR = ./include
LDIR = ./lib
libs = -lmingw32 -lSDL2main -lSDL2 -lSDL2_image
OBJS = $(patsubst $(SDIR)/%.cpp,$(ODIR)/%.o,$(wildcard $(SDIR)/*.cpp))
vpath %.cpp $(SDIR):$(SDIR)/Chip8
$(ODIR)/%.o : %.cpp
$(CC) -c -I $(IDIR) -o $# $^
$(OUTDIR)/% : $(wildcard obj/*.o)
$(CC) -L $(LDIR) -o $# $^ $(libs)
.PHONY : run
run :
$(OUTDIR)/$(OUT)
these are my source files
main.cpp
#include <iostream>
#include "Chip8/RomFileReader.h"
int main(){
RomReader romReader;
if(romReader.OpenFile("picture.ch8") == -1){
std::cout<<"could not open file !"<<std::endl;
return EXIT_FAILURE;
}
romReader.GetRom();
uint8_t * rom = romReader.ReturnRom();
int size = romReader.GetRomSize();
for(int i = 0; i<size; i++)
std::cout<<rom[i]<<std::endl;
free(rom);
romReader.FreeRom();
romReader.CloseReader();
}
ReadRomFile.h
#pragma once
#include <iostream>
#include <stdlib.h>
#include <inttypes.h>
#include <stdio.h>
class RomReader{
private :
FILE * m_Reader;
uint8_t * m_Rom;
public :
int OpenFile(const char * fileName);
void GetRom();
void FreeRom();
uint8_t * ReturnRom();
void CloseReader();
int GetRomSize();
};
RomFileReader.cpp
#include "RomFileReader.h"
int RomReader :: OpenFile(const char * fileName){
m_Reader = fopen(fileName,"rb");
if(m_Reader == NULL){
return -1;
} else
return 1;
}
int RomReader :: GetRomSize(){
int start = ftell(m_Reader);
fseek(m_Reader,0,SEEK_END);
int end = ftell(m_Reader);
fseek(m_Reader,0,SEEK_SET);
int size = end - size;
return size;
}
void RomReader :: GetRom(){
int size = GetRomSize();
if(m_Rom == NULL){
m_Rom = new uint8_t[size];
}
fread(m_Rom,1,size,m_Reader);
}
void RomReader :: FreeRom(){
free(m_Rom);
}
uint8_t * RomReader :: ReturnRom(){
return m_Rom;
}
void RomReader :: CloseReader(){
fclose(m_Reader);
}
this is the error I'm getting
./bin/chip8
could not open file !
make: *** [run] Error 1
I could use fstream but I'm more comfortable and confident in using FILE instead, I had done something similar in c and it worked without any issue.
I'm really not able to point at what is exactly not working.
my picture.ch8 is in the bin folder along with the executable, yet I get this error. What is it that I'm missing exactly?
Your main is calling
romReader.FreeRom();
I think m_Rom is not NULL. So the memory get freed, so the memory exception getting fired?!?
Set it to NULL in a constructor of your class:
class RomReader {
...
public :
RomReader() { m_Rom = NULL; };
~RomReader() { if ( m_Rom != NULL ) delete [] m_Rom; };
...
}
The basic problem you have is that wildcard expands to the files that exist when make reads the makefile. So when you build with a clean tree (where the obj directory is empty), it expands to nothing, so nothing gets built.
The upshot is that wildcard cannot be usefully used with intermediate files generated as part of your build as they might not exist yet when you build. It is only useful for finding source files.
You need instead something like
$(OUTDIR)/$(OUT): $(patsubst src/%.cpp, obj/%.o, $(wildcard src/*.cpp)) $(patsubst src/Chip8/%.cpp, obj/%.o, $(wildcard src/Chip8/*.cpp))
You also probably want to have your run target depend on the executable
run: $(OUTDIR)/$(OUT)
otherwise it will not (re)build it when you try to run.
Working on a c++ school project. Can't seem to get catch2 testing to work correctly.
I have a makefile where I compile my project
CC=clang++
CFLAGS=--std=c++11
objects = Event.o Simulation.o ListItem.o Node.o OrderedItem.o PartArrival.o
PriorityQueue.o Queue.o PartOne.o PartTwo.o PartZero.o PartialProduct.o
ProductArrival.o StartAssembly.o StartFinishingAssembly.o EndFinishingAssembly.o
StartMainAssembly.o EndMainAssembly.o EndAssembly.o Test_PriorityQueue.o
# .. etc .. put a list of your .o files here
# this rule will build A2 as the executable from the object files
all : A2main.o $(objects)
$(CC) $(CFLAGS) -o A2 $< $(objects)
# this rule will build A2test -- our testfile for the PriorityQueue
all : Test_PriorityQueue.cpp
clang++ --std=c++11 -o A2test Test_PriorityQueue.cpp
# this rule will build a .o file from a .cpp file.
%.o: %.cpp
$(CC) -c -o $# $< $(CFLAGS)
When this line runs clang++ --std=c++11 -o A2test Test_PriorityQueue.cpp I get this error:
Undefined symbols for architecture x86_64:
"Simulation::Simulation()", referenced from:
____C_A_T_C_H____T_E_S_T____4() in Test_PriorityQueue-1f17a8.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: *** [all] Error 1
Here's the code for the test file -- Test_PriorityQueue.cpp :
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do
this in one cpp file
#include "catch.hpp"
#include "Simulation.h"
#include "PartArrival.h"
#include "PriorityQueue.h"
#include <iostream>
using namespace std;
unsigned int Factorial( unsigned int number ) {
return number <= 1 ? number : Factorial(number-1)*number;
}
TEST_CASE( "Factorials are computed", "[factorial]" ) {
REQUIRE( Factorial(1) == 1 );
REQUIRE( Factorial(2) == 2 );
REQUIRE( Factorial(3) == 6 );
REQUIRE( Factorial(10) == 3628800 );
}
// debugging test
TEST_CASE("CATCH TEST"){
REQUIRE(1 == 1);
}
TEST_CASE("create PQ") {
cout << "PQ testcase" << endl;
Simulation *sim = new Simulation();
// PriorityQueue *pQue = new PriorityQueue();
// REQUIRE(pQue->getSize() == 0);
}
The first few tests run just fine when I comment out the last one "create PQ"
Once I include that I start getting these undefined symbol errors.
Been bashing my head against this for awhile. Some help would be very appreciated!!
Edit:
Simulation.h
#ifndef START_FILES_SIMULATION_H
#define START_FILES_SIMULATION_H
#pragma once
#include <fstream>
using namespace std;
class PriorityQueue; // Priority Queue
class Queue; // Queue class - provided to you
class Event; // Event - given to you.
class PartZero; // p0
class PartOne; // p1
class PartTwo; // p2
class PartialProduct; // partially assembled product
class Simulation {
private:
ifstream ifile; // input file to read.
int simulationTime; // what is the current time of the simulation?
PriorityQueue *eventList; // priority queue of Events.
Queue* productQueue; // queue of partially assembled products (for finishing station).
Queue** partQueues; // *array* of queues of parts for the stations.
int mainAssemblyTime; // how long does the main station take?
int finishingAssemblyTime; // how long does the main station take?
bool mainBusy; // is the main station busy?
bool finishingBusy; // is the finishing station busy?
int completelyAssembledItems; // number of items made
int cumulativeBuildTime; // the total amount of time to build all items
float averageBuildTime; // avg time to build item
public:
Simulation(); //TODO: build the part Queues when simulation is built
// TODO: you need methods to manipulate product and part queues.
// [add them here.]
// add to the respective queues
void addPartZero(PartZero *part);
void addPartOne(PartOne *part);
void addPartTwo(PartTwo *part);
void addPartialProduct(PartialProduct * product);
// dequeue the respective queues
int popMainParts(); // pops p0 and p1 and returns the earliest of arrivalTimes
void popPartZero();
void popPartOne();
void popPartTwo();
PartialProduct* popPartialProduct();
// functions that check if queues have parts in
bool partsInZero();
bool partsInOne();
bool partsInTwo();
bool partsInProduct();
int getCompletelyAssembledItems(); // getter
void completeAssemblyOfItem(); // adds one to completelyAssembledItems var
void updateCumulativeBuildTime(int time);
float getAvgBuildTime();
// main method for driving the simulation
void runSimulation(char *fileName);
// add an event to event queue.
void addEvent (Event*);
// read next arrival from file and add it to the event queue.
bool getNextArrival(); //TODO: add to sim.cpp
// getter and setter for simulation time
int getSimulationTime();
void setSimulationTime(int time);
// getters for assembly times
int getMainTime();
int getFinishingTime();
// getters and setters for station statuses.
bool isMainBusy();
bool isFinishingBusy();
void setMainStatus(bool);
void setFinishingStatus(bool);
};// class Simulation
#endif //START_FILES_SIMULATION_H
Simulation.cpp constructor :
// constructor
Simulation::Simulation() {
// init part queues
partQueues = reinterpret_cast<Queue **>(new Queue[3]);
partQueues[0] = new Queue();
partQueues[1] = new Queue();
partQueues[2] = new Queue();
// init event list
eventList = new PriorityQueue();
// init product queue
productQueue = new Queue();
// station status
mainBusy = false;
finishingBusy = false;
}
Since LLVM 8 (including current LLVM trunk, aka LLVM 9) I run into a problem when using the ORC JIT ExecutionEngine with functions which contain a call to the standard math library.
The JIT compiler is able to find the symbol for the function but fails to get the address for it in case the function makes a call to the math library.
I attach a simple exploit that shows the problem. The program test.cc reads in an IR file which contains a single function in LLVM's Intermediate Representation:
The function takes a single argument, a floating point number, and returns in case of
"func_works.ll" the argument itself, and in case of
"func_cos_fails.ll" the cosine of the argument.
I didn't implement the choice between the two files at runtime, so the program needs to be rebuilt when switching to the other case.
The program uses the standard KaleidoscopeJIT.h that comes with LLVM (except that I had to expose the Datalayout).
If you build the program with the "func_works.ll" and run it, the program succeeds with:
symbol found!
address found!
If you build the program with the "func_cos_fails.ll" and run it, the program fails with:
symbol found!
Failure value returned from cantFail wrapped call
UNREACHABLE executed at install/llvm-8.0-x86-debug/include/llvm/Support/Error.h:732!
This happens with LLVM 8 release and the current LLVM trunk.
Does anyone see what's going on?
This test was run on an x86 Linux Ubuntu system with LLVM configured with
cmake -G "Unix Makefiles" \
-DBUILD_SHARED_LIBS="ON" \
-DLLVM_ENABLE_RTTI="ON" \
-DLLVM_ENABLE_ZLIB="OFF" \
-DLLVM_ENABLE_TERMINFO="OFF" \
-DCMAKE_BUILD_TYPE="Debug" \
-DCMAKE_INSTALL_PREFIX=$CMAKE_INSTALL_PREFIX \
-DLLVM_TARGETS_TO_BUILD="X86" \
$SRC
test.cc:
#include "KaleidoscopeJIT.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Support/InitLLVM.h"
#include <iostream>
using namespace llvm;
using namespace llvm::orc;
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
EnableDebugBuffering = true;
LLVMContext Context;
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
InitializeNativeTargetAsmParser();
cl::ParseCommandLineOptions(argc, argv, "Kaleidoscope example program\n");
SMDiagnostic Err;
std::unique_ptr<llvm::Module> M = parseIRFile( "func_cos_fails.ll" , Err, Context, false);
//std::unique_ptr<llvm::Module> M = parseIRFile( "func_works.ll" , Err, Context, false);
if (!M) {
Err.print("IR parsing failed: ", errs());
return 0;
}
std::unique_ptr<KaleidoscopeJIT> TheJIT;
TheJIT = llvm::make_unique<KaleidoscopeJIT>();
auto H = TheJIT->addModule(std::move(M));
std::string MangledName;
llvm::raw_string_ostream MangledNameStream(MangledName);
llvm::Mangler::getNameWithPrefix(MangledNameStream, "func_ir" , TheJIT->getDL() );
if (auto Sym = TheJIT->findSymbol(MangledNameStream.str()))
{
std::cout << "symbol found!\n";
void* fptr = (void *)cantFail(Sym.getAddress());
std::cout << "address found!\n";
}
else
{
std::cout << "symbol not found!\n";
}
return 0;
}
func_cos_fails.ll:
source_filename = "module"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
declare float #cosf(float)
define float #func_ir(float %arg0) {
entrypoint:
%0 = call float #cosf(float %arg0)
ret float %0
}
func_works.ll:
source_filename = "module"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
define float #func_ir(float %arg0) {
entrypoint:
ret float %arg0
}
KaleidoscopeJIT.h:
#ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
#define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Mangler.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include <algorithm>
#include <map>
#include <memory>
#include <string>
#include <vector>
namespace llvm {
namespace orc {
class KaleidoscopeJIT {
public:
using ObjLayerT = LegacyRTDyldObjectLinkingLayer;
using CompileLayerT = LegacyIRCompileLayer<ObjLayerT, SimpleCompiler>;
KaleidoscopeJIT()
: Resolver(createLegacyLookupResolver(
ES,
[this](const std::string &Name) {
return ObjectLayer.findSymbol(Name, true);
},
[](Error Err) { cantFail(std::move(Err), "lookupFlags failed"); })),
TM(EngineBuilder().selectTarget()), DL(TM->createDataLayout()),
ObjectLayer(ES,
[this](VModuleKey) {
return ObjLayerT::Resources{
std::make_shared<SectionMemoryManager>(), Resolver};
}),
CompileLayer(ObjectLayer, SimpleCompiler(*TM)) {
llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
}
TargetMachine &getTargetMachine() { return *TM; }
VModuleKey addModule(std::unique_ptr<Module> M) {
auto K = ES.allocateVModule();
cantFail(CompileLayer.addModule(K, std::move(M)));
ModuleKeys.push_back(K);
return K;
}
void removeModule(VModuleKey K) {
ModuleKeys.erase(find(ModuleKeys, K));
cantFail(CompileLayer.removeModule(K));
}
JITSymbol findSymbol(const std::string Name) {
return findMangledSymbol(mangle(Name));
}
const DataLayout& getDL() const {
return DL;
}
private:
std::string mangle(const std::string &Name) {
std::string MangledName;
{
raw_string_ostream MangledNameStream(MangledName);
Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
}
return MangledName;
}
JITSymbol findMangledSymbol(const std::string &Name) {
#ifdef _WIN32
// The symbol lookup of ObjectLinkingLayer uses the SymbolRef::SF_Exported
// flag to decide whether a symbol will be visible or not, when we call
// IRCompileLayer::findSymbolIn with ExportedSymbolsOnly set to true.
//
// But for Windows COFF objects, this flag is currently never set.
// For a potential solution see: https://reviews.llvm.org/rL258665
// For now, we allow non-exported symbols on Windows as a workaround.
const bool ExportedSymbolsOnly = false;
#else
const bool ExportedSymbolsOnly = true;
#endif
// Search modules in reverse order: from last added to first added.
// This is the opposite of the usual search order for dlsym, but makes more
// sense in a REPL where we want to bind to the newest available definition.
for (auto H : make_range(ModuleKeys.rbegin(), ModuleKeys.rend()))
if (auto Sym = CompileLayer.findSymbolIn(H, Name, ExportedSymbolsOnly))
return Sym;
// If we can't find the symbol in the JIT, try looking in the host process.
if (auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(Name))
return JITSymbol(SymAddr, JITSymbolFlags::Exported);
#ifdef _WIN32
// For Windows retry without "_" at beginning, as RTDyldMemoryManager uses
// GetProcAddress and standard libraries like msvcrt.dll use names
// with and without "_" (for example "_itoa" but "sin").
if (Name.length() > 2 && Name[0] == '_')
if (auto SymAddr =
RTDyldMemoryManager::getSymbolAddressInProcess(Name.substr(1)))
return JITSymbol(SymAddr, JITSymbolFlags::Exported);
#endif
return nullptr;
}
ExecutionSession ES;
std::shared_ptr<SymbolResolver> Resolver;
std::unique_ptr<TargetMachine> TM;
const DataLayout DL;
ObjLayerT ObjectLayer;
CompileLayerT CompileLayer;
std::vector<VModuleKey> ModuleKeys;
};
} // end namespace orc
} // end namespace llvm
#endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H
for convenience I provide a Makefile:
LLVM_CONFIG = ${LLVM_INSTALL_PATH}
LLVM_CXXFLAGS = $(shell $(LLVM_CONFIG) --cxxflags)
LLVM_LDFLAGS = $(shell $(LLVM_CONFIG) --ldflags)
LLVM_LIBS = $(shell $(LLVM_CONFIG) --libs)
all: test
test.o: test.cc KaleidoscopeJIT.h
g++ -c -o $# $< $(LLVM_CXXFLAGS)
test: test.o
g++ -o $# $< $(LLVM_LDFLAGS) $(LLVM_LIBS)
clean:
rm -f *.o
rm -f test
I believe the solution to this (for llvm 7 and 8 anyway) was found here:
https://stackoverflow.com/a/56862433/2310373
Namely, replace:
[this](const std::string &Name) {
return ObjectLayer.findSymbol(Name, true);
},
With something like
[this](const std::string &Name) {
auto FoundSymbol = ObjectLayer.findSymbol(Name, true);
if (!FoundSymbol) {
if (auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(Name))
return JITSymbol(SymAddr, JITSymbolFlags::Exported);
}
return FoundSymbol;
},
I need to compile a C++ library to use with contiki on the Zolertia Re-Mote. I am trying a simple program first:
hello-world.c
#include "contiki.h"
#include "misc.h"
/*---------------------------------------------------------------------------*/
PROCESS(hello_world_process, "Hello world process");
AUTOSTART_PROCESSES(&hello_world_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(hello_world_process, ev, data)
{
PROCESS_BEGIN();
say_hello();
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
misc.cpp
/* C++ implementation */
#ifdef CONTIKI_TARGET_ZOUL
void* __dso_handle;
void* __exidx_end;
void* __exidx_start;
#endif
#include <iostream>
using namespace std;
void cpp_say_hello(){
cout << "Hello world!" << endl;
}
/* C wrapper */
extern "C"{
#include "misc.h"
void say_hello(){
cpp_say_hello();
}
}
misc.h
#ifndef _MISC_H_
#define _MISC_H_
/**
* \brief Prints hello to stdout
*/
void say_hello();
#endif /* _MISC_H_ */
Makefile
ifeq ($(TARGET),)
TARGET = native
endif
CONTIKI_PROJECT = hello-world
all: $(CONTIKI_PROJECT)
PROJECT_LIBRARIES = obj_$(TARGET)/misc.o
include $(CONTIKI)/Makefile.include
obj_$(TARGET)/misc.o: misc.cpp
#mkdir -p obj_$(TARGET)
$(TRACE_CXX)
$(Q)$(CXX) $(CFLAGS) $(CXXFLAGS) -c $^ -o $#
This (with some modifications to the contiki Makefiles: here) made possible for me to use C++ code for the 'native' target. However when i try to compile for the Zolertia Re-Mote platform (TARGET=zoul) i obtain the following error:
/usr/lib/gcc/arm-none-eabi/8.2.0/../../../../arm-none-eabi/bin/ld: hello-world.elf section `.ARM.extab.text._Z13cpp_say_hellov' will not fit in region `FLASH_CCA'
/usr/lib/gcc/arm-none-eabi/8.2.0/../../../../arm-none-eabi/bin/ld: region `FLASH_CCA' overflowed by 788 bytes
collect2: error: ld returned 1 exit status
make: *** [/home/wellsaid/contiki/cpu/cc2538/Makefile.cc2538:103: hello-world.elf] Error 1
rm hello-world.co obj_zoul/startup-gcc.o
Any way to fix this?
I just cant see what Im doing wrong here:
Q. Why is my library not being found by g++ when compiling the program with a shared object?
Im trying to include a shared library to my c++ program:
g++ -fpic -c sha.cpp
g++ -shared -o libsha.so sha.o
g++ main.cpp -o main -L. -lsha
where sha.cpp and sha.h are the library files and main.cpp is my program.
Ive tried the same with static library which works find:
g++ -static -c sha.cpp -o libsha.o
ar rcs libsha.a libsha.o
g++ main.cpp -o main -L. -lsha
The platform is cygwin on windows and here is the output:
rob#pc /cygdrive/c/src/a
$ g++ main.cpp -o shatest -L. -lsha
/usr/lib/gcc/i686-pc-cygwin/4.3.4/../../../../i686-pc-cygwin/bin/ld: cannot find -lsha
collect2: ld returned 1 exit status
Ive read all forum posts but the library is in the same folder!
$ ls
libsha.so main.cpp sha.cpp sha.h sha.o
The reason im doing this is that on another platform, a library is being created whereby when one object is called, it works, but the app crashes when the second object is being constructed. Im doing the above as a simple test! (annoyingly not so simple).
source files below:
main.cpp
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "sha.h"
void *thread_one( void *ptr );
void *thread_two( void *ptr );
main()
{
pthread_t thread1, thread2;
int iret1, iret2;
/* Create independent threads each of which will execute function */
iret1 = pthread_create( &thread1, NULL, thread_one, 0);
iret2 = pthread_create( &thread2, NULL, thread_two, 0);
/* Wait till threads are complete before main continues. Unless we */
/* wait we run the risk of executing an exit which will terminate */
/* the process and all threads before the threads have completed. */
pthread_join( thread1, NULL);
pthread_join( thread2, NULL);
printf("Thread 1 returns: %d\n",iret1);
printf("Thread 2 returns: %d\n",iret2);
exit(0);
}
void *thread_one( void *ptr )
{
printf("Run thread_one\n");
CObj1 obj;
}
void *thread_two( void *ptr )
{
printf("Run thread_two\n");
CObj2 obj;
}
sha.cpp
#include <stdio.h>
#include <stdlib.h>
#include "sha.h"
CObj1::CObj1()
{
printf("CObj1\n");
a = 10;
printf("CObj1: %d \n", a);
}
CObj2::CObj2()
{
printf("CObj2\n");
a = 10;
printf("CObj2: %d \n", a);
}
sha.h
#ifndef LIB
#define LIB
class CObj1
{
public:
CObj1();
private:
int a;
};
class CObj2
{
public:
CObj2();
private:
int a;
};
#endif