I started a new QT Creator project based on the SUBDIRS template and then recreated two subprojects; one DLL project and one exectuable that needs to use classes from the DLL.
I added the DLL library as an "Internal" library (and not as "external" because I figured it was in my build tree) to the executable. I have a class declared in my DLL and added the "export" specifier.
I am having trouble using it in the EXE project. It complains about unresolved external symbol. I tried adding "using MyClass;" at the top of main.cpp, but this didn't help. What do I need in place before I can use a class from my DLL project in the executable? Thanks!
Here is some code to add detail.
/////////// Main.cpp from Executable project ////////////////////////////////////////////////
#define USEDLL 1;
#include <QCoreApplication>
#include "../Library/myclass.h"
#include <QDebug>
#include <iostream>
//__declspec(dllimport) MyClass;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
__declspec(dllimport) MyClass g;
QString test;
test = MyClass::TheString();
return a.exec();
}
//////////////// Class Header in DLL ////////////////////////////////
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QString>
#ifdef ISDLL
#define DLL __declspec(dllexport)
#endif
#ifdef USEDLL
#define DLL __declspec(dllimport)
#endif
class DLL MyClass
{
public:
MyClass();
static QString TheString();
};
#endif // MYCLASS_H
////////////////// Class cpp from DLL project /////////////////////////
#define ISDLL 1;
#include "myclass.h"
MyClass::MyClass()
{
}
QString MyClass::TheString()
{
return "test";
}
//////////////////////////// Compiler output ////////////////////////////
11:09:59: Running steps for project Top...
11:09:59: Configuration unchanged, skipping qmake step.
11:09:59: Starting: "C:\Qt\Tools\QtCreator\bin\jom.exe"
cd Library\ && ( if not exist Makefile C:\Qt\5.1.1\msvc2010\bin\qmake.exe D:\Projects\Top\Library\Library.pro -spec win32-msvc2010 CONFIG+=debug CONFIG+=declarative_debug CONFIG+=qml_debug -o Makefile ) && C:\Qt\Tools\QtCreator\bin\jom.exe -f Makefile
C:\Qt\Tools\QtCreator\bin\jom.exe -f Makefile.Debug
cd App\ && ( if not exist Makefile C:\Qt\5.1.1\msvc2010\bin\qmake.exe D:\Projects\Top\App\App.pro -spec win32-msvc2010 CONFIG+=debug CONFIG+=declarative_debug CONFIG+=qml_debug -o Makefile ) && C:\Qt\Tools\QtCreator\bin\jom.exe -f Makefile
C:\Qt\Tools\QtCreator\bin\jom.exe -f Makefile.Debug
cl -c -nologo -Zm200 -Zc:wchar_t -Zi -MDd -GR -W3 -w34100 -w34189 -EHsc -DUNICODE -DWIN32 -DQT_QML_DEBUG -DQT_DECLARATIVE_DEBUG -DQT_CORE_LIB -I"C:\Qt\5.1.1\msvc2010\include" -I"C:\Qt\5.1.1\msvc2010\include\QtCore" -I"debug" -I"." -I"C:\Qt\5.1.1\msvc2010\mkspecs\win32-msvc2010" -Fodebug\ #C:\Users\philip\AppData\Local\Temp\main.obj.4512.0.jom
main.cpp
echo 1 /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 24 /* RT_MANIFEST */ "debug\\App.exe.embed.manifest">debug\App.exe_manifest.rc
if not exist debug\App.exe if exist debug\App.exe.embed.manifest del debug\App.exe.embed.manifest
if exist debug\App.exe.embed.manifest copy /Y debug\App.exe.embed.manifest debug\App.exe_manifest.bak
link /NOLOGO /DYNAMICBASE /NXCOMPAT /DEBUG /SUBSYSTEM:CONSOLE "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" /MANIFEST /MANIFESTFILE:debug\App.exe.embed.manifest /OUT:debug\App.exe #C:\Users\philip\AppData\Local\Temp\App.exe.4512.687.jom
main.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: static class QString __cdecl MyClass::TheString(void)" (__imp_?TheString#MyClass##SA?AVQString##XZ) referenced in function _main
debug\App.exe : fatal error LNK1120: 1 unresolved externals
jom: D:\Projects\build-Top-Desktop_Qt_5_1_1_MSVC2010_32bit-Debug\App\Makefile.Debug [debug\App.exe] Error 1120
jom: D:\Projects\build-Top-Desktop_Qt_5_1_1_MSVC2010_32bit-Debug\App\Makefile [debug] Error 2
jom: D:\Projects\build-Top-Desktop_Qt_5_1_1_MSVC2010_32bit-Debug\Makefile [sub-App-make_first-ordered] Error 2
11:10:00: The process "C:\Qt\Tools\QtCreator\bin\jom.exe" exited with code 2.
Error while building/deploying project Top (kit: Desktop Qt 5.1.1 MSVC2010 32bit)
When executing step 'Make'
11:10:00: Elapsed time: 00:01.
Did you put it to LIBS in pro-file? Check make files for linker flags.
Related
I am trying to implement my pthread_create function. After searching online I found few examples but I could not compile them and run the code.
I have these 2 files, first one is pthread.c
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <signal.h>
int (*original_pthread_create)(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) = NULL;
void load_original_pthread_create() {
void *handle = dlopen("libpthread-2.15.so", RTLD_LAZY);
char *err = dlerror();
if (err) {
printf("%s\n", err);
}
original_pthread_create = dlsym(handle, "pthread_create");
err = dlerror();
if (err) {
printf("%s\n", err);
}
}
int my_pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg) {
if (original_pthread_create == NULL) {
load_original_pthread_create();
}
printf("I am creating thread from my pthread_create\n");
return original_pthread_create(thread, attr, start_routine, arg);
}
I compiled this using the below command and got a shared object named libpthread.so
gcc pthread.c -o libmypthread.so -shared -fpic -ldl
Now the second file, main.cpp
#include <stdlib.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>
#include <ostream>
#include <iostream>
#include <thread>
#include <chrono>
#include <pthread.h>
#include <signal.h>
#include <functional>
#include <mutex>
#include <condition_variable>
#include <execinfo.h>
#include <sstream>
#include <dlfcn.h>
#include <unistd.h>
void *dummyThread(void *t)
{
// just spin/sleep until done
//std::cout<<"This thread ID is "<<std::this_thread::get_id()<<std::endl;
//long thID = (long) id;
printf("thread Id is pthread id is %lu\n", pthread_self());
while(!done)
{
sleep(10);
}
}
int main(int argc, char*argv[])
{
printf("Hello World!\n");
pthread_t ptid1, ptid2;
int ret1 = my_pthread_create(&ptid1, NULL, dummyThread, NULL);
int ret2 = my_pthread_create(&ptid2, NULL, dummyThread, NULL);
pthread_exit(NULL);
printf ("Goodbye Cruel World!\n");
}
To compile this above code, I use a Makefile
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g
CXXFLAGS=-std=c++17
LDFLAGS=-g -rdynamic
LDLIBS=-lpthread -ldl
SRCS=main.cpp
OBJS=$(subst .cpp,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
when I run make, I get this following error:
undefined reference to my_pthread_create(unsigned long*, pthread_attr_t const*, void* (*)(void*), void*)' /usr/bin/ld: /home/hgovindh/perf/main.cpp:: undefined reference to my_pthread_create(unsigned long*, pthread_attr_t const*, void*
()(void), void*)' collect2: error: ld returned 1 exit status make:
*** [Makefile:16: tool] Error 1
Now, how do I run this main.cpp so that it calls the my_pthread_create defined in the pthread.c file?
Are you familiar with C++'s name mangling? In C, if you have a function named foo -- regardless of the arguments it receives -- the symbol in the .o file is called foo. In C++, the name is mangled to include type information. This is how you can engage in method name overloading based on different arguments.
In your include file, you need to use
extern "C" {
....
}
This tells the C++ compiler that the symbols inside those braces are C symbols, and don't name-mangle them.
It will actually look something like this:
#ifdef __cplusplus
extern "C" {
#endif
With similar ifdef around the closing brace.
You should wrap your entire C .h file in this type of guard so it can be included in your C++ files. The other choice is to guard it when you include it, but it's better if you do the guard in the include file itself.
So you'll ultimately have something like this:
#ifdef __cplusplus
extern "C" {
#endif
void load_original_pthread_create();
int my_pthread_create(pthread_t *, const pthread_attr_t *, void *(*) (void *), void *);
#ifdef __cplusplus
}
#endif
You should be able do create different compilation rules depending on the file extension. Note that my preferred approach of using cmake is presented at the end of the answer.
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g
CXXFLAGS=-std=c++17
CFLAGS=-g
LDFLAGS=-g -rdynamic
LDLIBS=-lpthread -ldl
SRCS=main.cpp pthread.c
OBJS=$(addsuffix .o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
%.cpp.o: %.cpp
$(CXX) -c -o $# $(CPPFLAGS) $(CXXFLAGS) $<
%.c.o: %.c
$(CC) -c -o $# $(CFLAGS) $<
this appends the .o to the file name including extension to be able to tell .c files appart from .c files in the rules for the .o file.
Alternative: Let CMake generate the makefiles
CMake can take care of generating the project files for you. It will automatically choose some reasonable defaults and allows you to change the build system you're using without much effort e.g. to ninja instead of unix makefiles.
CMakeLists.txt
(Place in the directory containing the source files)
cmake_minimum_required(VERSION 3.16)
# compile features for c++17 only documented in v 3.16, but may be available earlier
project(Tool)
add_executable(tool
main.cpp
pthread.c
)
# make sure at least C++17 is used
target_compile_features(tool PRIVATE cxx_std_17)
set_target_properties(tool PROPERTIES
CXX_EXTENSIONS Off # no -std=gnu-...
# CXX_STANDARD 17 # require an exact standard (remove target_compile_feature, if commented in)
)
target_link_libraries(tool PRIVATE pthread ${CMAKE_DL_LIBS})
Building the project on linux should use gcc and g++ as default, unless you modified the environment variables to point to other compilers, in addition to using the generator "Unix Makefiles" by default.
Choose the name of a directory where CMake is free to modify/remove/overwrite any files without messing with your project files. I use build_release and build_debug below. From the directory containing the CMakeLists.txt file, execute the following commands to create makefile projects for the release and debug version respectively. This step is necessary only once.
cmake -D CMAKE_BUILD_TYPE=Debug -S . -B build_debug
cmake -D CMAKE_BUILD_TYPE=Release -S . -B build_release
Now the equivalent of running make all would be
cmake --build build_debug
cmake --build build_release
(alternatively you could change the working directory to build_debug or build_release and run make all, but the cmake --build ... version works with any Generator type even without changing the working directory.)
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 wrote an ftp client in C (using GNU make) and now want to use Qt to write a GUI for it.
While building, error occures:
error: symbol(s) not found for architecture x86_64
linker command failed with exit code 1 (use -v to see invocation)
Undefined symbols for architecture x86_64:
"showHelpMsg()", referenced from:
_main in main.o
My main.cpp looks like this:
include "client.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ftpClient w;
w.show();
showHelpMsg();
return a.exec();
}
client.h:
#include"common.h"
#include"handler.h"
#include"util.h" //These headers works fine while using gnu make
void showHelpMsg();
client.c:
include "client.h"
void showHelpMsg()
{
//....
}
And my project.pro:(auto generated by Qt)
SOURCES += main.cpp\
ftpclient.cpp \
client.c \
common.c \
handler.c \
util.c
HEADERS += ftpclient.h \
client.h \
common.h \
handler.h \
util.h
For reference, this is my previous makefile:
objects = client.o handler.o util.o common.o
server : $(objects)
cc -Wall -o client $(objects)
.PHONY : clean
clean :
rm client $(objects)
Try changing client.h to this:
#ifdef __cplusplus
extern "C" {
#endif
#include"common.h"
#include"handler.h"
#include"util.h"
void showHelpMsg();
#ifdef __cplusplus
}
#endif
The problem might be that the C++ compiler is expected showHelpMsg to be a C++ function with a mangled name, while the C compiler is only producing a normal C function with a normal name.
i'm trying to use clucene-0.9.21b and libcue-1.3.0 in Qt Creator on Kubuntu Lucid. this code is compilable:
project.pro
SOURCES += main.cpp
LIBS += -lcue
INCLUDEPATH += /usr/include/libcue-1.3/libcue
main.cpp
extern "C" {
#include <libcue.h>
}
int main(int argc, char *argv[]) {
return 0;
}
so is this:
project.pro
SOURCES += main.cpp
LIBS += -clucene
main.cpp
#include <CLucene.h>
int main(int argc, char *argv[]) {
return 0;
}
but not this one:
project.pro
SOURCES += main.cpp
LIBS += -lcue \
-clucene
INCLUDEPATH += /usr/include/libcue-1.3/libcue
main.cpp
extern "C" {
#include <libcue.h>
}
#include <CLucene.h>
int main(int argc, char *argv[]) {
return 0;
}
the latter generates the following errors:
Running build steps for project project...
Configuration unchanged, skipping QMake step.
Starting: /usr/bin/make -w
make: Entering directory `/home/user/project/project'
/usr/bin/qmake-qt4 -spec /usr/share/qt4/mkspecs/linux-g++ -unix CONFIG+=debug -o Makefile project.pro
make: Leaving directory `/home/user/project/project'
make: Entering directory `/home/user/project/project'
g++ -c -pipe -g -Wall -W -D_REENTRANT -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I/usr/include/libcue-1.3/libcue -I. -o main.o main.cpp
In file included from /usr/include/sys/stat.h:107,
from /usr/include/CLucene/StdHeader.h:76,
from /usr/include/CLucene.h:11,
from main.cpp:5:
/usr/include/bits/stat.h:88: error: field ‘st_atim’ has incomplete type
/usr/include/bits/stat.h:89: error: field ‘st_mtim’ has incomplete type
/usr/include/bits/stat.h:90: error: field ‘st_ctim’ has incomplete type
/usr/include/bits/stat.h:149: error: field ‘st_atim’ has incomplete type
/usr/include/bits/stat.h:150: error: field ‘st_mtim’ has incomplete type
/usr/include/bits/stat.h:151: error: field ‘st_ctim’ has incomplete type
main.cpp:6: warning: unused parameter ‘argc’
main.cpp:6: warning: unused parameter ‘argv’
make: *** [main.o] Error 1
make: Leaving directory `/home/user/project/project'
Exited with code 2.
Error while building project project
When executing build step 'Make'
why is that and how to make it work?
Ok, this time I got a chance to actually try it. Problem seems to be that libcue has a file called time.h in its include folder. So if you compile with -I/usr/include/libcue-1.4/libcue then you end up with libcue's time.h instead of libc's.
This works for me:
extern "C" {
#include <libcue/libcue.h>
}
#include <CLucene.h>
int main(int argc, char *argv[]) {
return 0;
}
and obviously compiling with -I/usr/include/libcue-1.4/ instead of -I/usr/include/libcue-1.4/libcue
What happens if you swap the cue and clucene includes around? It could be a problem with include order and I suspect mixing c and c++ may make include order even more important
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?