Still, is it impossible to use the external llvm custom pass on windows?
I can build the 'mypass.dll' on windows using LLVM libraries. And, I use these 2 way to use my pass.
clang.exe -Xclang -load -Xclang mypass.dll -c test.c
opt.exe -load -Xclang mypass.dll -mypass test.bc -o optimized_test.bc
But, Clang and opt didn't working well with my pass.
This mean, my pass can dump the llvm::Module in compilation time. and my pass can dump that on Linux. but, my pass didn't print anything on Windows.
Additionally, i already built the LLVM and Clang on Windows using CMake.
To avoid confusing, i'm writing my source code.
#include <iostream>
using namespace std;
#include <llvm/Pass.h>
#include <llvm/IR/Module.h>
using namespace llvm;
class SampleIRModule : public llvm::ModulePass {
public:
static char ID;
SampleIRModule() : llvm::ModulePass(ID) {}
bool runOnModule(llvm::Module &M);
};
bool SampleIRModule::runOnModule(llvm::Module &M) {
M.dump();
return false;
}
char SampleIRModule::ID = 0;
static RegisterPass<SampleIRModule> X("SampleIRModule", "SampleIRModule Pass");
And,here is my build command on windows.
cl /EHsc -ID:\LLVM\llvm-3.4.2\build_nmake\output/include -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -wd4146 -wd4180 -wd4244 -wd4267 -wd4345 -wd4351 -wd4355 -wd4503 -wd4624 -wd4800 -wd4291 -w14062 -we4238 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -c testpass.cpp
cl /D_USRDLL /D_WINDLL testpass.obj /link /DLL /OUT:testpass.dll D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMCore.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangAnalysis.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangARCMigrate.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangAST.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangASTMatchers.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangBasic.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangCodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangDriver.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangDynamicASTMatchers.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangEdit.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangFormat.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangFrontend.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangFrontendTool.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangIndex.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangLex.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangParse.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangRewriteCore.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangRewriteFrontend.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangSema.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangSerialization.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangStaticAnalyzerCheckers.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangStaticAnalyzerCore.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangStaticAnalyzerFrontend.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\clangTooling.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\libclang.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMAArch64AsmParser.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMAArch64AsmPrinter.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMAArch64CodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMAArch64Desc.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMAArch64Disassembler.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMAArch64Info.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMAArch64Utils.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMAnalysis.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMARMAsmParser.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMARMAsmPrinter.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMARMCodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMARMDesc.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMARMDisassembler.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMARMInfo.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMAsmParser.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMAsmPrinter.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMBitReader.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMBitWriter.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMCodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMCore.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMCppBackendCodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMCppBackendInfo.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMDebugInfo.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMExecutionEngine.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMHexagonAsmPrinter.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMHexagonCodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMHexagonDesc.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMHexagonInfo.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMInstCombine.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMInstrumentation.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMInterpreter.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMipa.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMipo.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMIRReader.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMJIT.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMLinker.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMLTO.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMMC.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMMCDisassembler.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMMCJIT.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMMCParser.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMMipsAsmParser.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMMipsAsmPrinter.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMMipsCodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMMipsDesc.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMMipsDisassembler.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMMipsInfo.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMMSP430AsmPrinter.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMMSP430CodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMMSP430Desc.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMMSP430Info.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMNVPTXAsmPrinter.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMNVPTXCodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMNVPTXDesc.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMNVPTXInfo.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMObjCARCOpts.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMObject.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMOption.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMPowerPCAsmParser.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMPowerPCAsmPrinter.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMPowerPCCodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMPowerPCDesc.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMPowerPCInfo.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMR600AsmPrinter.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMR600CodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMR600Desc.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMR600Info.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMRuntimeDyld.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMScalarOpts.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMSelectionDAG.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMSparcCodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMSparcDesc.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMSparcInfo.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMSupport.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMSystemZAsmParser.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMSystemZAsmPrinter.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMSystemZCodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMSystemZDesc.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMSystemZDisassembler.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMSystemZInfo.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMTableGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMTarget.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMTransformUtils.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMVectorize.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMX86AsmParser.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMX86AsmPrinter.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMX86CodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMX86Desc.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMX86Disassembler.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMX86Info.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMX86Utils.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMXCoreAsmPrinter.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMXCoreCodeGen.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMXCoreDesc.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMXCoreDisassembler.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LLVMXCoreInfo.lib D:\LLVM\llvm-3.4.2\build_nmake\output\lib\LTO.lib
Related
I have to create a Library for my work that contains Protobuf elements. It should run on every other PC without installing Protobuf. But I can not make the library run without having also the Protobuf files in the same folder (so I compile this files to and the user have to install Protobuf)
So I created for this a test program to demonstrate my problem:
->alias.proto
syntax = "proto3";
package aliasPackage;
message NumberSave{
int32 number = 1;
}
I created the .h and .cc with
protoc -I. --cpp_out=. alias.proto
->Backbone.h
#include "alias.pb.h"
class Backbone{
public:
Backbone();
~Backbone();
void save_Number(int value);
int get_Number();
private:
aliasPackage::NumberSave number;
};
->Backbone.cpp
#include "../header/Backbone.h"
#include <google/protobuf/stubs/common.h>
Backbone::Backbone()
{
number.set_number(0);
}
Backbone::~Backbone()
{
google::protobuf::ShutdownProtobufLibrary();
}
void Backbone::save_Number(int value)
{
number.set_number(value);
}
int Backbone::get_Number()
{
return number.number();
}
->Backbone.h for the lib
class Backbone{
public:
Backbone();
~Backbone();
void save_Number(int value);
int get_Number();
};
Creating the lib out of the files with this command (I thought about a static one, compiling the all independences into the file, but it seems not to work)
g++ -c --std=c++20 -O3 -DBUILD_SHARED_LIBS=ON -I/usr/local/include *.c* -lpthread -L/usr/local/lib -lprotobuf && ar rcs Backbone.sll *.o
->main.cpp
#include "../libs/lib/Backbone.h"
#include <iostream>
int main(){
auto backbone = new Backbone();
backbone->save_Number(5);
std::cout<<backbone->get_Number()<<std::endl;
delete backbone;
return 0;
}
Compile command
g++ -Wall -Wextra -Wpedantic --std=c++20 -O3 main.cpp -L. -l:../libs/lib/Backbone.sll
What am I doing wrong? What's the right command to create a Lib so that users can use it without installing Protobuf?
I have some code which expects type_index instances for a particular type created in a shared library and instances created in an executable (for the same particular type) to compare equal.
However, I have encountered a case where this does not work on QNX 7:
// idxlib.h
#include <typeindex>
#include <string>
#include <iostream>
#ifdef BUILD_LIB
#define LIB_EXPORT __attribute__((visibility("default")))
#else
#define LIB_EXPORT
#endif
template <typename T>
class Templ
{
};
class LIB_EXPORT LibType
{
public:
LibType();
template <typename T=int>
void templateMethod(int arg = 0) const
{
#ifndef REMOVE_INSTANTIATION
if (arg == 42)
{
// arg is never 42. This code path is not taken, but it instantiates the template
templateMethod();
}
#endif
if (mti == std::type_index(typeid(Templ<int>)))
std::cout << "Type indexes the same" << std::endl;
else
std::cout << "Type indexes NOT the same" << std::endl;
}
void normalMethod();
protected:
std::type_index mti;
};
// idxlib.cpp
#include "idxlib.h"
LibType::LibType() : mti(std::type_index(typeid(Templ<int>))) {}
void LibType::normalMethod()
{
templateMethod();
}
// sharedidx.cpp
#include "idxlib.h"
int main(int argc, char* argv[])
{
LibType lt;
if (argc == 65)
// argc is not 65, so don't call it, just instantiate it
lt.templateMethod();
lt.normalMethod();
return 0;
}
Build, scp and run:
QCC -Vgcc_ntox86_64 -g -fPIC -o idxlib.cpp.o -c idxlib.cpp -DBUILD_LIB -fvisibility=hidden -fvisibility-inlines-hidden
QCC -Vgcc_ntox86_64 -g -shared -o libidx.so idxlib.cpp.o
QCC -Vgcc_ntox86_64 -g -o sharedidx libidx.so sharedidx.cpp
scp -i ~/qnxinstall/id_rsa_qnx sharedidx libidx.so qnxuser#${QNXBOX}:/home/qnxuser/test
echo
echo "comparison fails:"
ssh -i ~/qnxinstall/id_rsa_qnx -t qnxuser#${QNXBOX} "cd /home/qnxuser/test && LD_LIBRARY_PATH=/home/qnxuser/test ./sharedidx"
QCC -Vgcc_ntox86_64 -g -shared -fPIC -o idxlib.cpp.o -c idxlib.cpp -DREMOVE_INSTANTIATION -DBUILD_LIB -fvisibility=hidden -fvisibility-inlines-hidden
QCC -Vgcc_ntox86_64 -g -shared -o libidx.so idxlib.cpp.o
QCC -Vgcc_ntox86_64 -g -o sharedidx libidx.so -DREMOVE_INSTANTIATION sharedidx.cpp -fvisibility=hidden -fvisibility-inlines-hidden
scp -i ~/qnxinstall/id_rsa_qnx sharedidx libidx.so qnxuser#${QNXBOX}:/home/qnxuser/test
echo
echo "comparison works:"
ssh -i ~/qnxinstall/id_rsa_qnx -t qnxuser#${QNXBOX} "cd /home/qnxuser/test && LD_LIBRARY_PATH=/home/qnxuser/test ./sharedidx"
Output:
Type indexes NOT the same
Type indexes the same
So, the type_index comparison fails when there is a template instantiation which contains a template instantiation of itself.
Is it a bug in QNX 7, or is my expectation (that it should ever work) wrong?
Is this code relying on implementation-defined behavior? Or undefined behavior?
QNX 7 QCC compiler is based on GCC 5.4 and uses a standard library based on libc++ from the same era. I have tested GCC 5.4 (and clang with libc++ and libstdc++) on Linux and I do not get the same behavior. I have also tried with and without _LIBCPP_NONUNIQUE_RTTI_BIT defined.
So, I'm assuming this is a result of the linker rather than the compiler. Could that be true?
Are the GCC compilers just "too helpful" in making this work on Linux across shared library boundaries?
I would never assume that RTTI works correctly on an embedded systems targeting toolchain. It might be supposed to work correctly, but almost nobody enables RTTI nor exceptions for embedded systems, so it'll get zero testing nor attention from support.
I'd suggest that you use a library based RTTI emulation, such as https://www.boost.org/doc/libs/1_74_0/doc/html/boost_typeindex.html which works on systems without RTTI, and is also fully deterministic and bounded in space and time unlike language RTTI.
Edited: ODR violation fixed.
Edited: I found that reordering the link directories (-L) fixed the problem but I don't know why.
The original order in the g++ command that was causing the problem was this:
-L/usr/local/lib
-L/usr/local/lib64
-L/usr/lib
-L/usr/lib/64
-L../../bin/Release
Moving -L../../bin/Release which contains the VampEngine.so fixed the problem, but why?
Edited Ends Here
I have two projects. VampEngine (A shared lib) and Application (the client). When I compile both of them on Windows (visual c++), VampEngine links just fine with the Application but on Linux I get undefined errors (g++).
I checked if the correct flags and paths are passed in the compiler's arguments and it seem right.
Also I'm pretty positive that I use extern "C" in both the dll implementation and in the client's decelerations.
Here is analytically the g++ makefile execution:
-------------- Clean: Debug|x64 in VampEngine (compiler: GNU GCC Compiler)---------------
Cleaned "VampEngine - Debug|x64"
-------------- Clean: Debug|x64 in Application (compiler: GNU GCC Compiler)---------------
Cleaned "Application - Debug|x64"
-------------- Build: Debug|x64 in VampEngine (compiler: GNU GCC Compiler)---------------
g++ -m64 -fPIC -I../../Depedencies/Cross-Plat/glm-0.9.9.5 -I/usr/include -I/usr/local/include -c /home/babaliaris/Deve/cpp/VampEngine/VampEngine/src/core.cpp -o ../../bin-int/Debug/VampEngine/x64/Debug/VampEngine/VampEngine/src/core.o
g++ -m64 -fPIC -I../../Depedencies/Cross-Plat/glm-0.9.9.5 -I/usr/include -I/usr/local/include -c /home/babaliaris/Deve/cpp/VampEngine/VampEngine/src/stb_image/stb_image.cpp -o ../../bin-int/Debug/VampEngine/x64/Debug/VampEngine/VampEngine/src/stb_image/stb_image.o
g++ -m64 -fPIC -I../../Depedencies/Cross-Plat/glm-0.9.9.5 -I/usr/include -I/usr/local/include -c /home/babaliaris/Deve/cpp/VampEngine/VampEngine/src/window.cpp -o ../../bin-int/Debug/VampEngine/x64/Debug/VampEngine/VampEngine/src/window.o
g++ -shared -L/usr/lib -L/usr/lib64 -L/usr/local/lib -L/usr/local/lib64 ../../bin-int/Debug/VampEngine/x64/Debug/VampEngine/VampEngine/src/core.o ../../bin-int/Debug/VampEngine/x64/Debug/VampEngine/VampEngine/src/stb_image/stb_image.o ../../bin-int/Debug/VampEngine/x64/Debug/VampEngine/VampEngine/src/window.o -o ../../bin/Debug/libVampEngine.so -s -shared -m64 -L/usr/lib64 -lGL -lGLEW -lglfw
Output file is ../../bin/Debug/libVampEngine.so with size 138.57 KB
-------------- Build: Debug|x64 in Application (compiler: GNU GCC Compiler)---------------
g++ -m64 -I../../Depedencies/Cross-Plat/glm-0.9.9.5 -I../../VampEngine/src -I/usr/include -I/usr/local/include -c /home/babaliaris/Deve/cpp/VampEngine/Application/src/main.cpp -o ../../bin-int/Debug/VampEngine/x64/Debug/Application/Application/src/main.o
g++ -L/usr/lib -L/usr/lib64 -L/usr/local/lib -L/usr/local/lib64 -L../../bin/Debug -o ../../bin/Debug/Application ../../bin-int/Debug/VampEngine/x64/Debug/Application/Application/src/main.o -s -m64 -L/usr/lib64 -lVampEngine
/usr/bin/ld: ../../bin-int/Debug/VampEngine/x64/Debug/Application/Application/src/main.o: in function `VampEngine::Core::Core(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, unsigned int, unsigned int)':
main.cpp:(.text._ZN10VampEngine4CoreC2ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEjj[_ZN10VampEngine4CoreC5ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEjj]+0x31): undefined reference to `Vamp_Core_Constructor'
/usr/bin/ld: ../../bin-int/Debug/VampEngine/x64/Debug/Application/Application/src/main.o: in function `VampEngine::Core::~Core()':
main.cpp:(.text._ZN10VampEngine4CoreD2Ev[_ZN10VampEngine4CoreD5Ev]+0x17): undefined reference to `Vamp_Core_Deconstructor'
/usr/bin/ld: ../../bin-int/Debug/VampEngine/x64/Debug/Application/Application/src/main.o: in function `VampEngine::Core::MainLoop()':
main.cpp:(.text._ZN10VampEngine4Core8MainLoopEv[_ZN10VampEngine4Core8MainLoopEv]+0x17): undefined reference to `Vamp_Core_MainLoop'
collect2: error: ld returned 1 exit status
Process terminated with status 1 (0 minute(s), 1 second(s))
4 error(s), 0 warning(s) (0 minute(s), 1 second(s))
Here is the core.cpp file which contains the implementation of the extern functions in the shared library:
#include "core.h"
#include "window.h"
#include <GLFW/glfw3.h>
#include "Engine/API.h"
namespace VampEngine
{
CoreImpl::CoreImpl(std::string title, unsigned int width, unsigned int height)
: window( new WindowImpl(title, width, height) )
{
}
CoreImpl::~CoreImpl()
{
delete window;
}
void CoreImpl::MainLoop()
{
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window->m_window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
/* Swap front and back buffers */
glfwSwapBuffers(window->m_window);
/* Poll for and process events */
glfwPollEvents();
}
}
}
extern "C" VAMP_API void* Vamp_Core_Constructor(const char* title, unsigned int width, unsigned int height)
{
return new VampEngine::CoreImpl(title, width, height);
}
extern "C" VAMP_API void Vamp_Core_Deconstructor(void* obj)
{
VampEngine::CoreImpl *object = (VampEngine::CoreImpl*)obj;
delete object;
}
extern "C" VAMP_API void Vamp_Core_MainLoop(void* obj)
{
VampEngine::CoreImpl* object = (VampEngine::CoreImpl*)obj;
object->MainLoop();
}
And this is the core.hpp which the client includes and compiles in his main.cpp file:
#ifndef VAMP_ENGINE_CORE_HPP
#define VAMP_ENGINE_CORE_HPP
#include <Engine/API.h>
#include <iostream>
extern "C"
{
VAMP_API void* Vamp_Core_Constructor(const char* title, unsigned int width, unsigned int height);
VAMP_API void Vamp_Core_Deconstructor(void* obj);
VAMP_API void Vamp_Core_MainLoop(void* obj);
}
namespace VampEngine
{
class Core
{
private:
void* m_core;
public:
Core(std::string title, unsigned int width, unsigned int height)
: m_core(Vamp_Core_Constructor(title.c_str(), width, height))
{
}
~Core()
{
Vamp_Core_Deconstructor(m_core);
}
void MainLoop()
{
Vamp_Core_MainLoop(m_core);
}
};
}
#endif
The VAMP_API macro is empty when compiled on Linux.
#ifndef VAMP_ENGINE_API_H
#define VAMP_ENGINE_API_H
//On Windows Platforms.
#ifdef VAMP_PLATFORM_WINDOWS
#ifdef VAMP_BUILD_DLL
#define VAMP_API _declspec(dllexport)
#else
#define VAMP_API _declspec(dllimport)
#endif
//Unix-Based Systems (GCC).
#else
#define VAMP_API
#endif
#endif
As you can see I use exactly the same names.
So what else can cause an undefined error?
I use arch linux x64, with gcc version:
$gcc --version
gcc (GCC) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Problem solved.
My code was just fine, the culprit was actually another libVampEngine.so library that was copied in /usr/lib by me. The linker was searching in the /usr/lib directory first and then the bin/ directory of my project, so instead of using the right .so file to link against, it was using the outdated one.
If anyone else is experiencing a problem like this and is almost certain that his code is fine, follow these steps:
1) Ensure that the linker is actually linking the correct shared library.
2) Check the library directories (-L) that the linker is searching for binaries.
-Make sure these directories do not contain a binary with the exact same name as
your own library.
3) Be carefull of outdated binary files. If the linker is linking against
one but your code has been updated, even if the program links correctly you will get
undefined behavior on runtime.
If I understood correctly from this document, it isn't prohibited to link an application built with newer compiler to a library build with an older one. Also I haven't found any information regarding ABI changes between GCC 4.8 and 4.9. However, here is a small example which causes a crash (due to an invalid vptr, apparently):
lib-48.h
#ifndef LIB_48_H
#define LIB_48_H
struct FooBase { virtual void foo() = 0; };
struct FooDerived : FooBase { virtual void foo() override {} };
void boom();
#endif // LIB_48_H
lib-48.cpp
#include "lib-48.h"
#include <memory>
void boom() {
auto x = std::make_shared<FooDerived>();
x->foo();
}
app-49.cpp
#include "lib-48.h"
#include <memory>
int main() {
std::make_shared<FooDerived>(); // Essential to reproduce
boom();
}
build & run
$ g++-4.8 -shared -fPIC -Wall -Wextra -O2 -std=c++11 lib-48.cpp -o liblib-48.so
$ g++-4.9 -std=c++11 -Wall -Wextra app-49.cpp -L. -llib-48 -Wl,-R'$ORIGIN' -o app-49
$ ./app-49
Segmentation fault (core dumped)
system information
Reproduced on x86_64 Ubuntu (both 14.04 and 16.04) with gcc 4.8.5 (Ubuntu 4.8.5-2ubuntu1~14.04.1) and gcc version 4.9.4 (Ubuntu 4.9.4-2ubuntu1~14.04.1).
Note that compiling both app and lib with the same compiler makes SIGSEGV go away. So does compiling with -O0 and few other modifications.
The question is simple: is it a bug, or am I doing something wrong?
I am trying to create a baremetal c++ application for a cortex-M4 device. My toolchain is ARM-GCC
I have noticed that the code size has shot up by 300kb which is 30% of the available flash size. There is a whole truckload of stuff from the standard libraries that gets linked in bloating TEXT, DATA and BSS areas.
Can this be reduced?
The application is the venerable blinky program with a :
- Blinky.c containing the C routine to toggle a port pin in a while loop
- Main.cpp containing the main() and a simple class with a constructor
- Device startup file which does program loading and yields control to main()
The c file is compiled using gcc while the cpp is compiled using g++. The linker is invoked via g++ to automatically link in stdlibc++(with the assumption that only necessary object fies from the stdlibc++ will be linked in).
I even have -fno-rtti and -fno-exceptions as compile options to g++, but the savings are a pittiance.
By the way, the generated binary works file.
This is the Main.cpp
#include <iostream>
using namespace std;
extern "C" void Toggle_Pin(uint8_t Speed);
void *__dso_handle = (void *)NULL;
void __cxa_atexit(void (*Arg)(void *), void *Arg2, void *Arg3){}
void __cxa_guard_acquire(void){}
void __cxa_guard_release(void){}
void __aeabi_atexit(void (*Arg)(void *), void *Arg2, void *Arg3){}
class Computer
{
public:
uint32_t aa;
uint32_t bb;
Computer();
};
Computer::Computer()
{
aa=0;
bb=0;
for(uint8_t i=0;i < 10; i++)
{
Toggle_Pin((uint8_t)100);
}
}
Computer a;
int main(void)
{
a.aa = 10;
Toggle_Pin();
}
And these are my compilation options provided to g++.
-O0 -ffunction-sections -Wall -fno-rtti -fno-exceptions -mfloat-abi=softfp -Wa,-adhlns="$#.lst" -c -fmessage-length=0 -mfpu=fpv4-sp-d16 -MMD -MP -MF"$(#:%.o=%.d)" -MT"$(#:%.o=%.d) $#" -mcpu=cortex-m4 -mthumb -g3 -gdwarf-2 -o "$#" "$<"
Linker options provided to g++:
-T LinkerScript.ld" -nostartfiles -L"Path to libraries" -Wl,-Map,"Project.map" -mcpu=cortex-m4 -mthumb -g3 -gdwarf-2 -o "Project.elf" "#makefile.rsp" $(USER_OBJS) $(LIBS)
Remove part with
#include <iostream>
using namespace std;
you don't need it. I guess it adds extra global objects / variables and might leave some definitions in binary.
Also use -Os
-Os
Optimize for size. -Os enables all -O2 optimizations that do not typically increase code size. It also performs further optimizations designed to reduce code size.