I'm a student trying to use Graphviz as an external library in my C project, using Windows. However, when I try to compile it, I receive undefined reference errors to the functions included in "gvc.h" and "cgraph.h". For example, agread and gvContext.
I've looked through many posts on the same topic but nothing suggested seemed to work for me as well.
Currently, I am only working on the Windows portion of my Makefile. Here it is in full:
.PHONY: all clean
#CFLAGS = `pkg-config --cflags glib-2.0`
#LDLIBS = `pkg-config --libs glib-2.0`
CFLAGS = -I"C:/Program Files/Graphviz/include/graphviz"
LDIR = -L"C:/Program Files/Graphviz/lib"
LIBS = -lgvc -lcgraph
binaries=sqlpsql
all: $(binaries)
sqlpsql: SQLP.c SQLPGrammar.y SQLPScanner.l SQLPtoSQL-main.c Preprocess.c Rules.c
ifeq ($(OS),Windows_NT)
win_bison -v -d SQLPGrammar.y
win_flex --nounput -D SQLPGrammar SQLPScanner.l
gcc -Wall -o sqlpsql SQLP.c SQLPtoSQL-main.c Preprocess.c Rules.c $(CFLAGS) $(LDIR) $(LIBS)
else
bison -v -d SQLPGrammar.y
flex --nounput -D SQLPGrammar SQLPScanner.l
gcc -Wall SQLP.c SQLPtoSQL-main.c Preprocess.c Rules.c -o sqlpsql
rm -f lex.yy.c SQLPGrammar.tab.c SQLPGrammar.tab.h
endif
clean:
-rm -f *.o *.output $(binaries)
On my computer, the header files are in: C:/Program Files/Graphviz/include/graphviz
The lib files are in: C:/Program Files/Graphviz/lib
I have added both locations to the Makefile using the -I and -L tags, as above.
Along with a very simple main function invoking the two functions (in another file), here is my SQLP.c file:
#include <stdio.h>
#include <gvc.h>
#include <cgraph.h>
#include "SQLP.h"
void generate_graph(){
FILE *fp;
fp = fopen("C:/Users/claud/Documents/UW/4A/Roseseed/test.dot", "w+");
fputs("digraph ERD {\n", fp);
fputs("graph [ rankdir = \"LR\" ];\n", fp);
fputs("ranksep=2;\n", fp);
fputs("\"SCOTT.DEPT\" [ label=\"<SCOTT.DEPT> SCOTT.DEPT|<PK_DEPT>DEPTNO \\l |DNAME \\l LOC \\l \" shape = \"record\" ];\n", fp);
fputs("\"SCOTT.EMP\" [ label=\"<SCOTT.EMP> SCOTT.EMP|<FK_DEPTNO>DEPTNO \\l |EMPNO \\l ENAME \\l JOB \\l MGR \\l STARTDATE \\l SAL \\l COMM \\l \" shape = \"record\" ];\n", fp);
fputs("\"SCOTT.DEPT\":\"PK_DEPT\"->\"SCOTT.EMP\":\"FK_DEPTNO\" [arrowhead = crow];}\n", fp);
fclose(fp);
export_graph();
}
void export_graph(){
FILE *fp;
fp = fopen("C:/Users/claud/Documents/UW/4A/Roseseed/test.dot", "r");
Agraph_t *g;
g = agread(fp, 0);
GVC_t *gvc;
gvc = gvContext();
gvLayout(gvc, g, "dot");
gvRender(gvc, g, "png",
fopen("C:/Users/claud/Documents/UW/4A/Roseseed/test.png", "w"));
gvFreeLayout(gvc, g);
agclose(g);
}
All other files compile properly because they do not include these header files.
And here is the full output of running make on Git Bash in the location of the Makefile:
$ make
win_bison -v -d SQLPGrammar.y
win_flex --nounput -D SQLPGrammar SQLPScanner.l
gcc -Wall -o sqlpsql SQLP.c SQLPtoSQL-main.c Preprocess.c Rules.c -I"C:/Program Files/Graphviz/include/graphviz" -L"C:/Program Files/Graphviz/lib" -lgvc -lcgraph
C:\Users\claud\AppData\Local\Temp\ccEwgb5N.o:SQLP.c:(.text+0x3abe): undefined reference to `_imp__agread'
C:\Users\claud\AppData\Local\Temp\ccEwgb5N.o:SQLP.c:(.text+0x3ac8): undefined reference to `_imp__gvContext'
C:\Users\claud\AppData\Local\Temp\ccEwgb5N.o:SQLP.c:(.text+0x3ae7): undefined reference to `_imp__gvLayout'
C:\Users\claud\AppData\Local\Temp\ccEwgb5N.o:SQLP.c:(.text+0x3b1b): undefined reference to `_imp__gvRender'
C:\Users\claud\AppData\Local\Temp\ccEwgb5N.o:SQLP.c:(.text+0x3b2f): undefined reference to `_imp__gvFreeLayout'
C:\Users\claud\AppData\Local\Temp\ccEwgb5N.o:SQLP.c:(.text+0x3b3c): undefined reference to `_imp__agclose'
collect2.exe: error: ld returned 1 exit status
make: *** [Makefile:13: sqlpsql] Error 1
It seems like the header files are found, just none of the functions are defined. What can I do to fix this and compile the project? I am a beginner, any help is greatly appreciated! :)
Related
I am trying to follow and convert [this][1] Googletest tutorial to work in windows and use Make for building. I am also trying to add a more typical directory structure.
[1]: https://www.eriksmistad.no/getting-started-with-google-test-on-ubuntu/
My directory structure:
D:.
│ makefile
│
├───bin
├───inc
│ whattotest.h
│
├───obj
├───src
│ whattotest.cpp
│
└───tests
tests.cpp
whattotest.h
#pragma once
double squareRoot(const double a);
whattotest.cpp
#include <math.h>
#include "whattotest.h"
double squareRoot(const double a) {
double b = sqrt(a);
if(b != b) { // nan check
return -1.0;
}else{
return sqrt(a);
}
}
tests.cpp
#include "whattotest.h"
#include <gtest/gtest.h>
TEST(SquareRootTest, PositiveNos) {
ASSERT_EQ(6, squareRoot(36.0));
ASSERT_EQ(18.0, squareRoot(324.0));
ASSERT_EQ(25.4, squareRoot(645.16));
ASSERT_EQ(0, squareRoot(0.0));
}
TEST(SquareRootTest, NegativeNos) {
ASSERT_EQ(-1.0, squareRoot(-15.0));
ASSERT_EQ(-1.0, squareRoot(-0.2));
}
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
makefile
CXX = g++
OBJ = obj
SRC = src
TESTS = tests
INC = inc
BIN = bin
LIBS= -lpthread
GTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\googletest\include\
LIBGTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\lib\libgtest.a
.PHONY : all
all: $(BIN)/runTests
$(BIN)/runTests: $(OBJ)/tests.o $(OBJ)/whattotest.o $(LIBGTEST)
#g++ -o runTests obj/tests.o obj/whattotest.o <path to libgtest.a> -pthread
$(CXX) -o $# $^ $(LIBS)
$(OBJ)/tests.o: $(TESTS)/tests.cpp
#g++ -I <path to gtest> -I inc -c tests.cpp -o tests.o
$(CXX) -I $(GTEST) -I $(INC) -c $< -o $#
$(OBJ)/whattotest.o: $(SRC)/whattotest.cpp
$(CXX) -I $(INC) -c $< -o $#
clean:
-rm $(OBJ)/*.o
-rm $(BIN)/*.exe
When I run this I get the following error:
g++ -I D:\myWorkspace\Gtest\googletest-release-1.11.0\googletest\include LIBGTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\lib\libgtest.a -I inc -c tests/tests.cpp -o obj/tests.o
g++: warning: LIBGTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\lib\libgtest.a: linker input file unused because linking not done
g++: error: LIBGTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\lib\libgtest.a: linker input file not found: Invalid argument
make: *** [makefile:19: obj/tests.o] Error 1
The way I thought this would run would be for Make to see the Rule for runTests requires tests.o, which does not exist, then drop down and use the Rule for creating that object file. After that, return to the Rule for runTests and complete.
The output looks like Make is combining the two rules together into some kind of amalgamation with -c and .cpp files combined. Which I believe is causing this error to occur.
I am confused as to why Make is doing this.
Check this:
GTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\googletest\include\
LIBGTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\lib\libgtest.a
By having a backslash at the end of the GTEST variable assignment you've continued that line to the next line, so GTEST contains the variable assignment on the next line as well (and LIBGTEST is not set).
You've basically written this:
GTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\googletest\include LIBGTEST=D:\myWorkspace\Gtest\googletest-release-1.11.0\lib\libgtest.a
You should not, in general, use backslashes in makefiles. You should use forward slashes for directory separators.
If you do want to use backslashes at the least you should not add them at the end of variable assignments.
I am trying to create a program in C++ that utilizes the rudeconfig library.
I run make, and get this:
g++ -o Homework5_executable helloworld.o -lrudeconfig -L/home/j/je/jea160530/hw5/libs
/bin/ld: cannot find -lrudeconfig
collect2: error: ld returned 1 exit status
make: *** [Homework5_executable] Error 1
I know this is happening because make is not recognizing the rudeconfig library, however I have followed the instructions on the rudeconfig site for install correctly.
Here is the code:
Makefile
#
# Set up info for C++ implicit rule
CXX = g++
CXXFLAGS = -Wall
CPPFLAGS = -I/home/012/j/je/jea160530/hw5/include
#
# Set up any Linker Flags
LDFLAGS = -L/home/012/j/je/jea160530/hw5/libs
#
# Set up libraries needer for compilation
LDLIBS = -lrudeconfig
#
# We choose the project name. This is used in building the file name for the backup target
PROJECTNAME = JesseAlotto_Homework5
#
# We choose the source files to include and name the output
SRCS = helloworld.cc
#
# We choose the name of the executable to be created
EXEC = Homework5_executable
#
# NORMALLY DON'T NEED TO CHANGE ANYTHING BELOW HERE
# =================================================
#
OBJS = $(SRCS:cc=o)
all: $(EXEC)
clean:
rm -f $(OBJS) *.d *~ \#* $(EXEC)
Makefile: $(SRCS:.cc=.d)
# Pattern for .d files.
# =====================
%.d:%.cc
#echo Updating .d Dependency File
#set -e; rm -f $#; \
$(CXX) -MM $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
# This is a rule to link the files. Pretty standard
# ================================================
$(EXEC): $(OBJS)
$(CXX) -o $(EXEC) $(OBJS) $(LDFLAGS) $(LDLIBS)
#echo Program compiled succesfully!
#
# Backup Target
# =============
backup: clean
#mkdir -p ~/backups; chmod 700 ~/backups
#$(eval CURDIRNAME := $(bash pwd))
#$(eval MKBKUPNAME := ~/backups/$(PROJECTNAME)-$(shell date +'%Y.%m.%d-%H:%M:%S').tar.gz)
#echo
#echo Writing Backup file to: $(MKBKUPNAME)
#echo
#tar -zcvf $(MKBKUPNAME) ./$(CURDIRNAME)
#chmod 600 $(MKBKUPNAME)
#echo
#echo Done!
#
# Include the dependency files
# ============================
-include $(SRCS:.cc=.d)
helloworld.cc
#include <string>
#include <iostream>
#include <fstream>
#include <tclap/CmdLine.h>
#include <map>
#include <stdlib.h>
#include <rude/config.h>
using namespace rude;
int main(int argc, char *argv[]){
std::string nextLine;
std::map<int, std::string> optionMap;
try{
std::cout << "hello world!";
//Command Line Variable
TCLAP::CmdLine cmd("CS3377.002 Program 5", ' ', "1.0");
//Switch Args
TCLAP::SwitchArg daemonSwitch("d", "daemon", "Run in daemon mode (forks to run as a daemon).", cmd, false);
//Unlabeled Value Args
TCLAP::UnlabeledValueArg<std::string> infileArg("infile", "The name of the configuration file. Defaults to cs3376dirmond.conf", true, "cs3376dirmond.conf", "config filename", false);
//Add leftover flags to cmdLine object
cmd.add(infileArg);
//Parse the command line
cmd.parse(argc, argv);
//Create an enumeratedlist for the mapping
enum flags {DAEMON, INFILE};
//Map keys and values to map
if (daemonSwitch.getValue()){
optionMap[DAEMON] = "1";
}
else{
optionMap[DAEMON] = "0";
}
optionMap[INFILE] = infileArg.getValue();
//Load input file
std::ifstream inputFile;
inputFile.open(optionMap[INFILE].c_str(), std::ios::in);
if(!inputFile){
std::cerr << "Error: no input file" << std::endl;
}
//============================================PARSE CONFIGURATION FILE==========================
Config config;
config.load("cs3376dirmond.conf");
//==============================================================================================
inputFile.close();
return 0;
} catch (TCLAP::ArgException &e) //catch any exceptions
{ std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;}
}
The error is caused by this command:
g++ -o Homework5_executable helloworld.o -lrudeconfig -L/home/j/je/jea160530/hw5/libs
not by make itself.
The error means that the linker isn’t finding librudeconfig.so in the library search path. From your comments, it turns out the library is named rudeconfig.so instead, so you need to specify
LDLIBS = -l:rudeconfig.so
instead of -lrudeconfig (which always expands to librudeconfig.so or librudeconfig.a).
Ideally, the library should be installed as librudeconfig.so...
I tried to compile the new v1alpha2 of the grpc Google Assistant SDK.
For that i ran make (with cpp language output) inside the Google Assistant git repository, wich generated my *.pb.cc and *.ob.h files. Then i tried to compile the /google/api, /google/type *.pb.cc files into .o files, that i can link into my basic project. (the embedded_assistant.proto has two import statements: import "google/api/annotations.proto"; import "google/type/latlng.proto";).
I also tried to compile it with /google/protobuf and /google/rpc.
It is automated by a makefile, and at this command i get the following error:
make generated command:
g++ -c -I/usr/local/include -pthread -I./googleapis/gens -I./grpc -std=c++11 googleapis/gens/google/api/auth.pb.cc -o googleapis/gens/google/api/auth.pb.o
output:
googleapis/gens/google/api/auth.pb.cc:552:23: error: cannot cast '::google::protobuf::RepeatedPtrField< ::google::api::AuthenticationRule>' to its private base class
'google::protobuf::internal::RepeatedPtrFieldBase'
rules_.InternalSwap(&other->rules_);
^
/usr/local/include/google/protobuf/repeated_field.h:776:41: note: declared private here
class RepeatedPtrField PROTOBUF_FINAL : private internal::RepeatedPtrFieldBase {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
googleapis/gens/google/api/auth.pb.cc:553:27: error: cannot cast '::google::protobuf::RepeatedPtrField< ::google::api::AuthProvider>' to its private base class
'google::protobuf::internal::RepeatedPtrFieldBase'
providers_.InternalSwap(&other->providers_);
^
/usr/local/include/google/protobuf/repeated_field.h:776:41: note: declared private here
class RepeatedPtrField PROTOBUF_FINAL : private internal::RepeatedPtrFieldBase {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
googleapis/gens/google/api/auth.pb.cc:936:30: error: cannot cast '::google::protobuf::RepeatedPtrField< ::google::api::AuthRequirement>' to its private base class
'google::protobuf::internal::RepeatedPtrFieldBase'
requirements_.InternalSwap(&other->requirements_);
^
/usr/local/include/google/protobuf/repeated_field.h:776:41: note: declared private here
class RepeatedPtrField PROTOBUF_FINAL : private internal::RepeatedPtrFieldBase {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 errors generated.
make: *** [googleapis/gens/google/api/auth.pb.o] Error 1
thanks for any help and wish you a nice holiday
I setup everything completly new, now it works. I think maybe some include pathes were wrong. (but i don't really know, why it works now)
checkout https://github.com/googleapis/googleapis
cd into googleapis and checkout submodules with git submodule update --init
run make LANGUAGE=cpp
compile alle the *.pb.cc files in subdirectorys googleapis/gens/google/api and googleapis/gens/google/type and googleapis/gens/google/assistant/embedded/v1alpha2
put them together into an archive
link that archive together with grpc and protobuf librarys and some sample code into an executable. protobuf and grpc need to be installed, like here in step 3: c++ v1alpha1 assistant sdk example
i put this dirty makefile together. not really nice, but does the trick.
GOOGLEAPIS_GENS_PATH = ./googleapis/gens
API_CCS = $(shell find ./googleapis/gens/google/api -name '*.pb.cc')
TYPE_CCS = $(shell find ./googleapis/gens/google/type -name '*.pb.cc')
ASSISTANT_CCS = $(shell find ./googleapis/gens/google/assistant/embedded/v1alpha2 -name '*.pb.cc')
CC = g++
FLAGS += -I$(GOOGLEAPIS_GENS_PATH)
FLAGS += -std=c++11
SRC = $(API_CCS) $(TYPE_CCS) $(ASSISTANT_CCS)
OBJ = $(SRC:%.cc=%.o)
PROG_FLAGS = $(FLAGS)
PROG_FLAGS += `pkg-config --libs grpc++ grpc`
PROG_FLAGS += `pkg-config --cflags --libs protobuf`
PROG_FLAGS += -I./googleapis/gens/google/assistant/embedded/v1alpha2
PROG_SRC = main.cpp
PROG_OBJ = $(PROG_SRC:%.cpp=%.o)
all: prog
prog: assistant_api.ar $(PROG_SRC)
$(CC) $(PROG_FLAGS) $(PROG_SRC) assistant_api.ar -o prog
assistant_api.ar: $(OBJ)
ar r $# $?
$(OBJ): $(SRC)
$(CC) -c $(FLAGS) $*.cc -o $*.o
clean:
rm -rf *.o assistant_api.ar $(OBJ)
I'm trying to setup Mingw-w64 as the mex compiler in MATLAB 2013a. My laptop has x86_64 architecture and runs windows 7. The program I want to compile uses c++11-style threading, so I'm using mingw-w64 version 4.9.0 with posix threads.
According to instruction I found here and here, I modified my mexopts.bat file. The code seems to compile successfully, but the linker reports an error. Does anyone have suggestions what I might be doing wrong?
By the way, I tried using gnumex to setup the compiler, but that didn't work either.
Here's the output and error message that MATLAB gives:
>mex -v Gomoku_mex.cpp
-> Default options filename found in C:\Users\Bas\AppData\Roaming\MathWorks\MATLAB\R2013a
-> Options file = C:\Users\Bas\AppData\Roaming\MathWorks\MATLAB\R2013a\mexopts.bat
MATLAB = C:\Program Files\MATLAB\R2013a
-> COMPILER = x86_64-w64-mingw32-g++
-> Compiler flags:
COMPFLAGS = -std=c++11 -fexceptions -I"C:\Program Files\MATLAB\R2013a\extern\include"
OPTIMFLAGS = -O3 -fexpensive-optimizations -DNDEBUG
DEBUGFLAGS = -g -Wall -Wextra
arguments =
Name switch = -o
-> Pre-linking commands=
-> LINKER = x86_64-w64-mingw32-g++
-> Link directives:
LINKFLAGS = -shared mex.def -L"C:\Program Files\MATLAB\R2013a\bin\win64" -static-libstdc++
LINKDEBUGFLAGS = -g -Wall
LINKFLAGSPOST = -lmex -lmx -lmat -lmwlapack -lmwblas
Name directive = -o "Gomoku_mex.mexw64"
File link directive =
Lib. link directive =
Rsp file indicator =
-> Resource Compiler =
-> Resource Linker =
----------------------------------------------------------------
--> x86_64-w64-mingw32-g++ -std=c++11 -fexceptions -I"C:\Program Files\MATLAB\R2013a\extern\include" -oC:\Users\Bas\AppData\Local\Temp\mex_r7jRw0\Gomoku_mex.obj -I"C:\Program Files\MATLAB\R2013a\extern\include" -I"C:\Program Files\MATLAB\R2013a\simulink\include" -O3 -fexpensive-optimizations -DNDEBUG -DMX_COMPAT_32 Gomoku_mex.cpp
C:\Users\Bas\AppData\Local\Temp\cc4hwD3A.o:Gomoku_mex.cpp:(.text+0x9d1c): undefined reference to `mxGetPr'
C:\Users\Bas\AppData\Local\Temp\cc4hwD3A.o:Gomoku_mex.cpp:(.text+0x9d83): undefined reference to `mxCreateDoubleScalar'
C:/PROGRA~1/mingw-w64/x86_64-4.9.0-posix-seh-rt_v3-rev2/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/4.9.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\Bas\AppData\Local\Temp\cc4hwD3A.o: bad reloc address 0x0 in section `.pdata$_ZNKSt5ctypeIcE8do_widenEc'
collect2.exe: error: ld returned 1 exit status
C:\PROGRA~1\MATLAB\R2013A\BIN\MEX.PL: Error: Compile of 'Gomoku_mex.cpp' failed.
Error using mex (line 206)
Unable to complete successfully.
Edit: As extra information, this is my mexopts.bat file. I got this directly from one of the two links above and modified directory & compiler names and added -std=c++11
set MATLAB=%MATLAB%
set PATH=%PATH%;C:\PROGRA~1\mingw-w64\x86_64-4.9.0-posix-seh-rt_v3-rev2\mingw64\bin
set MW_TARGET_ARCH=win64
rem ********************************************************************
rem Compiler parameters
rem ********************************************************************
set COMPILER=x86_64-w64-mingw32-g++
set COMPFLAGS=-std=c++11 -fexceptions -I"%MATLAB%\extern\include"
set OPTIMFLAGS=-O3 -fexpensive-optimizations -DNDEBUG
set DEBUGFLAGS=-g -Wall -Wextra
set NAME_OBJECT=-o
rem ********************************************************************
rem Linker parameters
rem ********************************************************************
set PRELINK_CMDS1=echo EXPORTS > mex.def & echo mexFunction >> mex.def
set LINKER=x86_64-w64-mingw32-g++
set LINKFLAGS= -static-libstdc++ -shared mex.def -L"%MATLAB%\bin\win64" -L"%MATLAB%\extern\lib\win64\microsoft"
set LINKFLAGSPOST= -lmex -lmx -lmat -lmwlapack -lmwblas
set LINKOPTIMFLAGS=-O3
set LINKDEBUGFLAGS= -g -Wall
set LINK_FILE=
set LINK_LIB=
set NAME_OUTPUT=-o "%OUTDIR%%MEX_NAME%%MEX_EXT%"
set RSP_FILE_INDICATOR=
set POSTLINK_CMDS1=del mex.def
Take the following configuration file that I'm using (you'll need to adjust the path pointing to MinGW-w64 location accordingly):
mingw_mexopts.bat
#echo off
set MATLAB=%MATLAB%
set MW_TARGET_ARCH=win64
set PATH=C:\MinGW-w64\mingw64\bin;%PATH%
set COMPILER=x86_64-w64-mingw32-g++
set COMPFLAGS=-c -m64 -mwin32 -mdll -Wall -std=c++11 -DMATLAB_MEX_FILE
set OPTIMFLAGS=-DNDEBUG -O2
set DEBUGFLAGS=-g
set NAME_OBJECT=-o
set LINKER=x86_64-w64-mingw32-g++
set LINKFLAGS=-shared -L"%MATLAB%\extern\lib\win64\microsoft" -L"%MATLAB%\bin\win64"
set LINKFLAGSPOST=-lmx -lmex -lmat
set LINKOPTIMFLAGS=-O2
set LINKDEBUGFLAGS=-g
set LINK_FILE=
set LINK_LIB=
set NAME_OUTPUT=-o "%OUTDIR%%MEX_NAME%%MEX_EXT%"
Next here is a simple MEX-function that uses C++11 threads:
test.cpp
#include "mex.h"
#include <vector>
#include <thread>
void say_hello(int tid) {
mexPrintf("hello from %d\n", tid);
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
std::vector<std::thread> threads;
for (int i=0; i<10; i++) {
threads.push_back(std::thread(say_hello, i));
}
for(auto& t : threads) {
t.join();
}
}
Finally we compile and run it in MATLAB:
>> mex -f mingw_mexopts.bat -largeArrayDims test.cpp
>> setenv('PATH', ['C:\MinGW-w64\mingw64\bin;', getenv('PATH')])
>> test
hello from 0
hello from 4
hello from 2
hello from 3
hello from 5
hello from 1
hello from 6
hello from 8
hello from 7
hello from 9
Note that if you're going to deploy this to another machine, you'll have to also copy a few dependent DLL's (you'll find them in MinGW bin folder), and place them next to the MEX-file. Use Dependency Walker to list them. In my case it was:
libstdc++-6.dll
libgcc_s_seh-1.dll
libwinpthread-1.dll
I am using GCC 4.8.2 with MATLAB R2014a running on 64-bit Windows.
Note these error messages:
C:\Users\Bas\AppData\Local\Temp\cc4hwD3A.o:Gomoku_mex.cpp:(.text+0x9d1c): undefined reference to `mxGetPr'
C:\Users\Bas\AppData\Local\Temp\cc4hwD3A.o:Gomoku_mex.cpp:(.text+0x9d83): undefined reference to `mxCreateDoubleScalar'
The library search path for libmex, libmx, libmat, ... is not added in your link command. The directory in your script is the bin directory containing DLLs. That's not correct here.
LINKFLAGS = -shared mex.def -L"C:\Program Files\MATLAB\R2013a\extern\lib\win64\microsoft" -static-libstdc++
I am trying to link a static library while creating my program executable using the below makefile..
IDIR =../inc
CC=g++ -g
CFLAGS=-I$(IDIR)
WFLAGS=-Wall -W
OFLAGS=-O3
DLINUX=-D_LINUX
ODIR=obj
LDIR =../lib
LIBS=-lm
_OBJ = testclient.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/testclient.o: testclient.c
$(CC) -c $< $(CFLAGS) -o $#
$(ODIR)/file2.o: file2.c
$(CC) -c $< $(CFLAGS) -o $#
testclient: $(OBJ)
$(CC) -o $# $^ $(LIBS) -lccn -pthread
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~
I have tried everything available from changing the order of the '-lccn' parameter to checking whether the function exists in the library (nm libccn.a gives the required function ccn_create() in it). The error returned is :
obj/testclient.o: In function `main':
/root/testClient/src/testclient.c:91: undefined reference to `ccn_create()'
The library libccn.a is in /usr/local/lib. I have also tried changing the directory path and then using -L flag to look in that location. Doesn't work either. :( ..Any ideas as to how can i make it work ?
My guess is that libccn.a is a C library and the header that you use are not designed to be imported by a C++ compiler (there is no extern "C" { } block surrounding the function definition).
C++ supports function overloading by mangling name of function. When you put a function in a extern "C" { } block, C++ disable name mangling (and thus disable overloading). Here, in your error message, the function mentioned is ccn_create(). Notice the (), this means that the function type is known, and thus the named looked up was a mangled name.
When you do nm libccn.a you see the real name, and it is ccn_create. That is not a mangled name. So to fix this, you'll need to surround the function definition in a export "C" { } block. The easiest way to do that is to surround the #include in such a block.
BTW, you can reproduce the error by doing this.
$ echo 'void ccn_create();' > ccn.h
$ echo '#include "ccn.h"
void ccn_create() { }' > ccn.c
$ echo '#include "ccn.h"
int main () {
ccn_create();
return 0;
}' > main.cc
$ gcc -o ccn.o -c ccn.c
$ g++ -o main main.cc ccn.o
Undefined symbols for architecture x86_64:
"ccn_create()", referenced from:
_main in cc8XnYRq.o
ld: symbol(s) not found for architecture x86_64
$ echo 'extern "C" {
#include "ccn.h"
}
int main () {
ccn_create();
return 0;
}' > main.cc
$ g++ -o main main.cc ccn.o