Here is my problem:
I need to design a program in F# that, from a C++ program, performs simple 3D vector calculations. I don't share the calculations on the codes below because the problem stops at creating the vectors according to the printfn.
So I think it's an error, but my schoolmate on macOS has no problem with this and can run the code correctly. I deduced that it was a Windows problem, probably because of the pointers. So I'm relying on you to help me.
Thanks a lot.
PS: dotnet version 7.0.101
clang version 15.0.5
Vector3.cpp
#include <math.h>
#include <iostream>
using namespace std;
int main()
{
return 0;
}
class Vector3
{
public:
double X;
double Y;
double Z;
Vector3(double x, double y, double z) : X(x), Y(y), Z(z) {}
};
extern "C" Vector3* CreateVector3(double x, double y, double z)
{
Vector3* v = new Vector3(x, y, z);
return v;
}
Program.fs
open System.Runtime.InteropServices
[<StructLayout(LayoutKind.Sequential)>]
printfn("test 1: Launching the program")
type Vector3 =
val mutable X: double
val mutable Y: double
val mutable Z: double
new(x, y, z) = { X = x; Y = y; Z = z }
[<DllImport("compiledVector3.exe")>]
extern Vector3 CreateVector3(double x, double y, double z)
[<DllImport("compiledVector3.exe")>]
extern double GetX(Vector3 v)
[<DllImport("compiledVector3.exe")>]
extern double GetY(Vector3 v)
[<DllImport("compiledVector3.exe")>]
extern double GetZ(Vector3 v)
[<DllImport("compiledVector3.exe")>]
extern double distanceTo(Vector3 v,Vector3 v2)
[<DllImport("compiledVector3.exe")>]
extern void vectorMovement(Vector3 v,double plusx, double plusy, double plusz)
[<DllImport("compiledVector3.exe")>]
extern Vector3 midpoint(Vector3 v,Vector3 v2)
[<DllImport("compiledVector3.exe")>]
extern double percentDistance(Vector3 pos1, Vector3 pos2, double percent)
printfn("test 2: DLL imported")
let FstVector= CreateVector3(0.0, 0.0, 0.0)
let SndVector= CreateVector3(1.0, 2.0, 3.0)
printfn("test 3: Vectors created")
I tried to launc the Program.fs with a basic dotnet run command, expecting to see in my terminal the following lines:
test 1: Launching the program
test 2: DLL imported
test 3: Vectors created
but there isn't the third line.
Terminal
PS C:\Users\AlexisLasselin\Documents\GitHub\2022-2023-project-3-harfang3d-binding-Project-4-group\CppToFs\Vector3> dotnet run
test 1: Launching the program
test 2: DLL imported
PS C:\Users\AlexisLasselin\Documents\GitHub\2022-2023-project-3-harfang3d-binding-Project-4-group\CppToFs\Vector3>
I think the compilation of your dll file is made for architecture x32 and you want to compile with a x64 windows architecture :
To compile a DLL using g++ for a 64-bit architecture, you can use the following command:
g++ -shared -o <filename>.dll -m64 <source files>
Replace with the desired name of the DLL, and with the names of the source files that make up the DLL.
The -shared option tells g++ to create a shared library (i.e., a DLL), and the -o option specifies the name of the output file. The -m64 option specifies that you want to compile for a 64-bit architecture.
Related
for example, i have a function declare in test.hpp and definition in test.cpp:
float sum(float x, float y)
i want to change function:
float sum(float x, float y,float z)
in clion,we can edit int this window:
in vscode, i should change function declaration in hpp and than chang functin definition in cpp which is really inconvient.
i have searched,but i only found that only visual studio 2022 support this.
I want to see the mangled name of this code. How should I do it.
I have tried this by compiling the code using G++ compiler and seeing output as ./a.out but nothing is printed. I have read about dumpbin.exe in windows but I do not have any idea about Mac.
nameMangling.cpp
// This demonstrate the nameMangling of function to make their signature.
int square(int x){
return x*x;
}
double square(double y){
return y*y;
}
void nothing1(int a, float b, char c, int &d){
}
void nothing2(char a, int b, float &c, double &d){
}
int main(){
return 0; // Indicate successful termination
}
The expected result is
__Z6squarei
__Z6squared
__Z8nothing1ifcRi
__Z8nothing2ciRfRd
_main
Any light on my problem will be Appreciated. Thank You
If you don't have binutils installed, install that package.
This is probably a good place to start: Install binutils on Mac OSX
Then nm a.out should show you the mangled names and nm -C a.out should show you the demangled names.
I am trying to expose a C++ DLL to Excel using mac. The DLL was written and compiled with Xcode 4 and I am using Excel 2011.
For simple functions, extern "C" does the work and I am able to use the dylib in Excel. Specifically, if the C++ code is something like
extern "C"
{
double sumC( double a, double b)
{
return a + b;
}
}
and the VBA code is:
Private Declare Function addFunction _
Lib "Macintosh HD:Users:SVM:Documents:Excel:lib:libTestDLLtoVBA.dylib" _
Alias "sumC" (ByVal a As Double, ByVal b As Double) As Double
Function Addition(a As Double, b As Double)
Addition = addFunction(a, b)
End Function
everything works fine. But, I am interested in exposing to Excel more complex code with classes defined in header files - as in the example below - and in that case Excel returns #VALUE!. My C++ code is something like this
header file:
#ifndef TestDLLtoVBA_TestFunction_h
#define TestDLLtoVBA_TestFunction_h
class AdditionVBATest{
public:
AdditionVBATest(){};
AdditionVBATest( double ){ m_AdditionResult = 0.0; }
~AdditionVBATest(){};
void setResult( double nAddition ){ m_AdditionResult = nAddition; }
double getResult(){ return m_AdditionResult; }
void addFunct( double x, double y, double &nResult );
double addFunct( double, double );
private:
double m_AdditionResult;
};
double addFunctionC( double a, double b);
#endif
cpp file:
#include <iostream>
#include "TestFunction.h"
void AdditionVBATest::addFunct(double x, double y, double &nResult)
{
nResult = 0.0;
nResult = x + y;
AdditionVBATest::setResult(nResult);
}
double AdditionVBATest::addFunct( double a, double b )
{
double nResult(0.0);
AdditionVBATest addCompute;
addCompute.AdditionVBATest::addFunct(a, b, nResult);
AdditionVBATest addResult;
return addResult.getResult();
}
And finally this is the file that contains the function I would like to expose to Excel:
#include <iostream>
#include "TestFunction.h"
extern "C"
{
double addFunctionC( double a, double b)
{
AdditionVBATest *resAddition;
double result(0.0);
result = resAddition->AdditionVBATest::addFunct(a, b);
return result;
}
}
I tried to use the same dylib in a C++ app and works fine, so I believe it is something related to exposing the library through VBA.
The VBA code I used is
Private Declare Function addFunction _
Lib "Macintosh HD:Users:SVM:Documents:Excel:lib:libTestDLLtoVBA.dylib" Alias "addFunctionC" _
(ByVal a As Double, ByVal b As Double) As Double
Function Addition(a As Double, b As Double)
Addition = addFunction(a, b)
End Function
Any help would be greatly appreciated.
This is of course not necessary but to simplify I will assume from now on that your header file and both source files are in the same directory, and that all future commands are executed in this directory. Then replace in both source files
#include "TestFunction.h"
with
#include "./TestFunction.h"
Then, compile as follows :
g++ -m32 -Wall -g -c ./TestFunction.cpp -o ./TestFunction.o
g++ -m32 -dynamiclib ./file.cpp ./TestFunction.o -o ./libTestDLLtoVBA.dylib
where
g++ is your gcc. I guess it is clang's one, on my computer it is gcc 5.2.0, but both should work fine
file.cpp is the source file containing the declaration of addFunctionC
the -m32 option asks to produce a 32 bits dylib, as excel/VBA on mac are 32 bits
Now do a nm -gU libTestDLLtoVBA.dylib and you will see a line with _addFunctionC showing that the function addFunctionC is exported indeed.
In the VBA, declare as follows :
Declare Function addFunctionC Lib "/Path/to/your/libTestDLLtoVBA.dylib" (ByVal x As Double, ByVal y As Double) As Double
Function Addition(a As Double, b As Double)
Addition = addFunction(a, b)
End Function
and it should work. This was a great source of inspiration.
Now, if you don't want to used command line and want to use XCode for instance, I would say that the only thing you have to take care of is to ensure that XCode produces a 32 bits dylib, as excel/VBA are 32 bits only on mac OS X. I really think that this 32 bits stuff is your problem.
You likely want to read up on COM automation objects. Sometimes known as "OLE" or "ActiveX". It's essentially a way to expose classes and objects written in C++ to other programming languages.
For scripting environments (VBA and Javascript), the traditional way to do this is by registering a COM object that exposes an IDispatch interface.
Some links to get you started:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms221375(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ms221326(v=vs.85).aspx
Don't get hung up on the details of "controls" and embedded UI windows. Foucs on getting a simple COM object class and interface declared in an IDL, generate a typelib, implement a C++ class that implements the interface and IDispatch. ATL (Active Template Library) makes this stuff easy.
I am learning C++ and have been given an assignment to create a Vector3D class. When I try to compile main.cpp using G++ on OSX I get the following error message. Why would this be?
g++ main.cpp
Undefined symbols for architecture x86_64:
"Vector3DStack::Vector3DStack(double, double, double)", referenced from:
_main in cc9dsPbh.o
ld: symbol(s) not found for architecture x86_64
main.cpp
#include <iostream>;
#include "Vector3DStack.h";
using namespace std;
int main() {
double x, y, z;
x = 1.0, y = 2.0, z = 3.0;
Vector3DStack v (x, y, z);
return 0;
}
Vector3DStack.h
class Vector3DStack {
public:
Vector3DStack (double, double, double);
double getX ();
double getY ();
double getZ ();
double getMagnitude();
protected:
double x, y, z;
};
Vector3DStack.cpp
#include <math.h>;
#include "Vector3DStack.h";
Vector3DStack::Vector3DStack (double a, double b, double c) {
x = a;
y = b;
z = c;
}
double Vector3DStack::getX () {
return x;
}
double Vector3DStack::getY () {
return y;
}
double Vector3DStack::getZ () {
return z;
}
double Vector3DStack::getMangitude () {
return sqrt (pow (x, 2) * pow (y, 2) * pow (z, 2));
}
You have to compile and link your Vector3DStack.cpp as well. Try:
g++ main.cpp Vector3DStack.cpp -o vectortest
This should create an executable called vectortest.
Pass the implementation of Vector3D to the compiler:
g++ main.cpp Vector3DStack.cpp
This will produce executable called a.out on Linux and Unix systems. To change the executable name use -o option:
g++ -o my_program main.cpp Vector3DStack.cpp
This is the simplest possible way of building your program. You should learn a bit more - read about make program, or even cmake.
I had ran into a similar issue when writing my own implementation of a hashTable with templates.
In your main.cpp, just include "Vector3DStack.cpp", which includes Vector3DStack.h, instead of just including Vector3DStack.h.
In my case, since templates, as we know, are evaluated at compile time, having templatized (including fully specialized) methods in the class as part of the cpp file (where they are defined) need to be known to the compiler. Some of the C++ gotchas.. so much to remember, easy to forget the little things.
Mostly likely you've already got our solution, thanks to the answers posted earlier, but my $0.02 anyways.
Happy C++ Programming!
I'm trying to recompile my old game which links the Ruby library, but I keep getting this error:
ruby18-mt-static-release.lib(math.obj): error LNK2001: unresolved
external symbol _hypot
Is there any workaround for this that doesn't require me finding the source code to this library and rebuilding it?
I'm using Visual Studio 2010 and the latest DirectX SDK.
I had a similar problem. Apparently hypot used to be a linkable function but is now (I have VS 2010) an inline function that calls _hypot. In math.h this is the only function where this is done. I don't have source for the existing library I am using and it has hypot linked to it so it can't use the inline version. If I just define hypot myself the linker says it is already defined. The following works to fix this:
Edit math.h and comment or ifdef out the inline version of hypot.
Implement hypot as extern "C" double hypot(double x, double y) {return _hypot(x, y);}
Relink
Ugly, but it solved the problem.
You are using the MT-STATIC version of the library. You need to make sure your project (Code Generation->Runtime Library) is also set to multithreaded, not multithreaded DLL. Conversely, you can find the MT-DLL version of the library. Either way, the runtime library (either MT or MTD) must be consistent across your program and all libraries you want to link.
http://msdn.microsoft.com/en-us/library/abx4dbyh(v=vs.80).aspx
This is an old question but I have a new workaround that do not need to modify math.h.
I met a similar issue when I tried to static link 'msvcrt-ruby18-static.lib' into my own dll in Visual Studio 2012 (VS2012). I got the this error:
'unresolved external symbol __imp__hypot referenced in function _math_hypot'
Thanks to Matt's answer, we know it is caused by the change of 'math.h'.
This function:
double hypot(double _X, double _Y)
before vs2010 it was a dll export function declared by keyword like this:
extern "C" __declspec(dllexport) double __cdecl hypot(...)
since vs2010, it became an inline function:
static __inline double __CRTDECL hypot(...)
Luckily in VS2012, the inline function is wrapped by a macro RC_INVOKED. You can try this public domain implantation to let it link:
#define RC_INVOKED
#include <ruby.h>
extern "C" __declspec(dllexport)
double hypot(double x, double y)
{
if (x < 0) x = -x;
if (y < 0) y = -y;
if (x < y) {
double tmp = x;
x = y; y = tmp;
}
if (y == 0.0) return x;
y /= x;
return x * sqrt(1.0+y*y);
}
[NOTICE] My project is a DLL and I use the dllexport keyword directly. It seems the '__imp__' prefix cannot be defined directly. I tried to define a function named __imp__hypot(...) and I failed.
Implement hypot() yourself. It's pretty straightforward:
double hypot(double x, double y) {
double ax = fabs(x), ay = fabs(y);
double xy = x/y, yx = y/x;
return ax > ay
? ax * sqrt(1.0 + yx*yx)
: ay * sqrt(1.0 + xy*xy);
}