Linking PHP-CPP library to a Linux project in Visual Studio 2017 - c++

I have a small C++ test project which should result in a .so-library on Windows Subsystem for Linux (WSL, more or less = Ubuntu 14.x). In order to get a PHP extension the current version of the PHP-CPP library is linked to the project. The compiler is g++ 4.8 on Linux and remotely operated from Visual Studio. In the properties I add -fpic for compiling and -lphpcpp to link libphpcpp.so. Using the old version of Visual Studio 2017 (until 02/2018) everything behaved well and the build was fine.
After updating to the current version of Visual Studio 2017 (15.5.6, 02/2018) the build ends in numerous linking errors of the same type: /usr/bin/ld : error : relocation x has invalid symbol index y, where the numbers x and y vary.
I have no idea what happens here.
The small project consists uses the ideas from here:
DLL in Visual Studio
... and ...
PHP-CPP first extension
The linking options recorded in Visual Studio:
-o"C:\Users\Robert\Documents\Lightning Talk\MathFuncs\MathFuncs\bin\x64\Release\MathFuncs.out" "3600000"
-Wl,-z,relro -Wl,--print-map -Wl,-z,noexecstack -Wl,--trace -Wl,
--verbose -Wl,--no-undefined "g++" -l"phpcpp" -Wl,-z,now
The last lines of the ld/g++ error messages:
1>/usr/bin/ld : error : relocation 15 has invalid symbol index 13
1>/usr/bin/ld : error : relocation 16 has invalid symbol index 13
1>/usr/bin/ld : error : relocation 17 has invalid symbol index 13
1>/usr/bin/ld : error : relocation 18 has invalid symbol index 13
1>/usr/bin/ld : error : relocation 19 has invalid symbol index 21
1>/usr/bin/ld : error : relocation 0 has invalid symbol index 2
1>/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crt1.o : error :
1>collect2 : error : ld returned 1 exit status
1>Die Erstellung des Projekts "MathFuncs.vcxproj" ist abgeschlossen -- FEHLER.
My code is here:
MathFuncs.h:
#pragma once
#include <stdexcept>
using namespace std;
// This class is exported from the MathFuncsDll.dll
class MathFuncs
{
public:
// Returns a + b
static double Add(double a, double b);
// Returns a - b
static double Subtract(double a, double b);
// Returns a * b
static double Multiply(double a, double b);
// Returns a / b
// Throws const std::invalid_argument& if b is 0
static double Divide(double a, double b);
};
double MathFuncs::Add(double a, double b)
{
return a + b;
}
double MathFuncs::Subtract(double a, double b)
{
return a - b;
}
double MathFuncs::Multiply(double a, double b)
{
return a * b;
}
double MathFuncs::Divide(double a, double b)
{
if (b == 0)
{
throw invalid_argument("b cannot be zero!");
}
return a / b;
}
... and main.cpp:
#include <iostream>
#include <phpcpp.h>
#include "MathFuncs.h"
Php::Value phpAdd(Php::Parameters &params)
{
auto a(0.0);
a = params[0];
auto b(0.0);
b = params[1];
return MathFuncs::Add(a, b);
}
Php::Value phpSubtract(Php::Parameters &params)
{
auto a(0.0);
a = params[0];
auto b(0.0);
b = params[1];
return MathFuncs::Subtract(a, b);
}
Php::Value phpMultiply(Php::Parameters &params)
{
auto a(0.0);
a = params[0];
auto b(0.0);
b = params[1];
return MathFuncs::Multiply(a, b);
}
Php::Value phpDivide(Php::Parameters &params)
{
auto a(0.0);
a = params[0];
auto b(0.0);
b = params[1];
return MathFuncs::Divide(a, b);
}
extern "C" {
/**
* Function that is called by PHP right after the PHP process
* has started, and that returns an address of an internal PHP
* strucure with all the details and features of your extension
*
* #return void* a pointer to an address that is understood by PHP
*/
PHPCPP_EXPORT void *get_module()
{
// static(!) Php::Extension object that should stay in memory
// for the entire duration of the process (that's why it's static)
static Php::Extension extension("phpMathFuncs", "1.0"); // To be humble, we can change the version number to 0.0.1
extension.add<phpAdd>("Add", {
Php::ByVal("a", Php::Type::Float),
Php::ByVal("b", Php::Type::Float)
});
extension.add<phpSubtract>("Subtract", {
Php::ByVal("a", Php::Type::Float),
Php::ByVal("b", Php::Type::Float)
});
extension.add<phpMultiply>("Multiply", {
Php::ByVal("a", Php::Type::Float),
Php::ByVal("b", Php::Type::Float)
});
extension.add<phpDivide>("Divide", {
Php::ByVal("a", Php::Type::Float),
Php::ByVal("b", Php::Type::Float)
});
// return the extension
return extension;
}
}

In the project properties/general the had been "application (.out)". Changing it to "dynamic library (.so)" solved the problem.

Related

boost::unit_test::data::random(-FLT_MAX, FLT_MAX) only generates +Infinity

I'm using boost::unit_test::data::random (with boost-1.61.0_1 installed) and I'm having some issues generating random floats using boost::unit_test::data::random(-FLT_MAX,FLT_MAX). It only seems to generate +Infinity.
Through trial and error, I found that I could generate random floats in [-FLT_MAX,-FLT_MAX * 2^-25) and [-FLT_MAX * 2^-25, FLT_MAX) separately, which gives me a possible work-around, but I'm still curious as to what I'm doing wrong trying to generate floats in [-FLT_MAX, FLT_MAX).
#define BOOST_TEST_MODULE example
#include <boost/test/included/unit_test.hpp>
#include <boost/test/data/monomorphic.hpp>
#include <boost/test/data/test_case.hpp>
#include <cfloat>
inline void in_range(float const & min, float const & x, float const & max) {
BOOST_TEST_REQUIRE(min <= x);
BOOST_TEST_REQUIRE(x < max);
}
static constexpr float lo{-FLT_MAX / (1024.0 * 1024.0 * 32.0)};
// this test passes
namespace bdata = boost::unit_test::data;
BOOST_DATA_TEST_CASE(low_floats, bdata::random(-FLT_MAX, lo) ^ bdata::xrange(100), x,
index) {
#pragma unused(index)
in_range(-FLT_MAX, x, lo);
}
// this test passes
BOOST_DATA_TEST_CASE(high_floats, bdata::random(lo, FLT_MAX) ^ bdata::xrange(100), x,
index) {
#pragma unused(index)
in_range(lo, x, FLT_MAX);
}
// this test fails
BOOST_DATA_TEST_CASE(all_floats, bdata::random(-FLT_MAX, FLT_MAX) ^ bdata::xrange(100), x,
index) {
#pragma unused(index)
in_range(-FLT_MAX, x, FLT_MAX);
}
results in:
$ ./example
Running 300 test cases...
example.cpp:9: fatal error: in "all_floats": critical check x < max has failed [inf >= 3.40282347e+38]
Failure occurred in a following context:
x = inf; index = 0;
...
example.cpp:9: fatal error: in "all_floats": critical check x < max has failed [inf >= 3.40282347e+38]
Failure occurred in a following context:
x = inf; index = 99;
*** 100 failures are detected in the test module "example"
boost::unit_test::data::random uses std::uniform_real_distribution, which has the requirement:
Requires: a ≤ b and b - a ≤ numeric_limits<RealType>::max().
In your case, b - a is 2 * FLT_MAX, which is +Inf in float.
You could use your workaround, or you could generate in double and cast back to float.

Returning an object with same name as the class generates linker error

I'm using C++ and Visual Studio Professional 2013 to write a wrapper for the Windows API (to make it easier to read). When I try to compile the solution, I get two linker errors related to the Intersect function in the wRectangle class. I commented out the function to see what the cause of the problem was, and the solution compiled and ran fine. From this, I determined that it was because the return type was an object of the class name (i.e. The Intersect function in the wRectangle class returns a wRectangle object). Moving the implementation of the Intersect function to its prototype in Rectangle.h fixed the issue, but I would prefer to keep the implementation in Rectangle.cpp. Any way to solve this?
Relevant files, most of the comments have been removed since they serve no relevance:
Rectangle.h:
#include <Windows.h>
#include "Typedefs.h"
#include "Window.h"
namespace windows_API_Wrapper
{
#ifndef RECTANGLE_H
#define RECTANGLE_H
class wRectangle
{
public:
wRectangle();
wRectangle(uInt32 xMin, uInt32 xMax, uInt32 yMin, uInt32 yMax);
void operator=(wRectangle &assignment);
void operator=(Window assignment);
boolean operator!=(wRectangle nonComparable);
wRectangle Intersect(wRectangle source1, wRectangle source2);
void Normalize();
private:
rectangle rect; //A wRectangle structure (typedef of a RECT strucure), for internal use only
};
#endif //RECTANGLE_H
}
Rectangle.cpp:
#include "Rectangle.h"
using namespace windows_API_Wrapper;
wRectangle::wRectangle()
{
this->rect.left = 0;
this->rect.top = 0;
this->rect.right = 0;
this->rect.bottom = 0;
}
void wRectangle::operator=(wRectangle &assignment)
{
this->rect.left = assignment.rect.left;
this->rect.top = assignment.rect.top;
this->rect.right = assignment.rect.right;
this->rect.bottom = assignment.rect.bottom;
}
void wRectangle::operator=(Window assignment)
{
if (GetClientRect(assignment.Get(), &this->rect) == 0)
MessageBox(null, "Failed to assign window dimensions to wRectangle!", "ERROR", MB_ICONEXCLAMATION);
}
boolean wRectangle::operator==(wRectangle comparable)
{
return EqualRect(&this->rect, &comparable.rect);
}
boolean wRectangle::operator!=(wRectangle nonComparable)
{
return !EqualRect(&this->rect, &nonComparable.rect);
}
wRectangle wRectangle::Intersect(wRectangle source1, wRectangle source2)
{
wRectangle destination;
IntersectRect(&destination.rect, &source1.rect, &source2.rect);
return destination;
}
void wRectangle::Normalize()
{
if (this->rect.top > this->rect.bottom)
{
uInt32 temp = this->rect.top;
this->rect.top = this->rect.bottom;
this->rect.bottom = temp;
}
if (this->rect.left > this->rect.right)
{
uInt32 temp = this->rect.left;
this->rect.left = this->rect.right;
this->rect.right = temp;
}
}
Error 1:
error LNK2019: unresolved external symbol "public: __thiscall
windows_API_Wrapper::wRectangle::wRectangle(class windows_API_Wrapper::wRectangle const &)" (??
0wRectangle#windows_API_Wrapper##QAE#ABV01##Z) referenced in function "public: class
windows_API_Wrapper::wRectangle __thiscall windows_API_Wrapper::wRectangle::Intersect(class
windows_API_Wrapper::wRectangle,class windows_API_Wrapper::wRectangle)" (?
Intersect#wRectangle#windows_API_Wrapper##QAE?AV12#V12#0#Z)
File: G:\Visual Studio Projects\Windows API Wrapper\Windows API Wrapper\Rectangle.obj
Project: Windows API Wrapper
Error 2:
error LNK1120: 1 unresolved externals
File: G:\Visual Studio Projects\Windows API Wrapper\Debug\Windows API Wrapper.exe
Project: Windows API Wrapper
This is because you have not defined
wRectangle(uInt32 xMin, uInt32 xMax, uInt32 yMin, uInt32 yMax);

How to use parallel_for_each function and __declspec(dllexport) attribute at the same time

Recently I wrote a function like this:
#include "amp.h"
#define DLLExport __declspec(dllexport)
using namespace concurrency;
namespace dll
{
class SomeMethods
{
public:
static DLLExport double CalcConvolution(double* mask, double* map, int size)
{
array_view<const double, 1> avMask(size, mask);
array_view<double, 1> avOMap(size, map);
array_view<double, 1> avCache(size, new double[size]);
avCache.discard_data();
parallel_for_each(
avCache.extent,
[=](index<1> idx) restrict(amp)
{
avCache[idx] = avMask[idx] * avOMap[idx];
}
);
avCache.synchronize();
double sum = 0;
auto cache = avCache.data();
for (int i = 0; i < size; i++)
sum += cache[i];
return sum;
}
};
}
Visual Studio reported the following error:
error C1451: Failed to generate debug information when compiling the call graph for the concurrency::parallel_for_each
As soon as I removed the DLLEXPORT modifier, the error disappeared but I cannot export this function to my other programs any more.
How do I solve this problem?
We have observed error C1451 being reported when TMP environmental variable value contains non-ASCII characters. The temporary workaround is to set the user environmental variable to e.g. C:\tmp.

NLOpt with windows forms

I am suffering serious problems while trying to use nlopt library (http://ab-initio.mit.edu/wiki/index.php/NLopt_Tutorial) in windows forms application. I have created following namespace which runs perfectly in console application.
#include "math.h"
#include "nlopt.h"
namespace test
{
typedef struct {
double a, b;
} my_constraint_data;
double myfunc(unsigned n, const double *x, double *grad, void *my_func_data)
{
if (grad) {
grad[0] = 0.0;
grad[1] = 0.5 / sqrt(x[1]);
}
return sqrt(x[1]);
}
double myconstraint(unsigned n, const double *x, double *grad, void *data)
{
my_constraint_data *d = (my_constraint_data *) data;
double a = d->a, b = d->b;
if (grad) {
grad[0] = 3 * a * (a*x[0] + b) * (a*x[0] + b);
grad[1] = -1.0;
}
return ((a*x[0] + b) * (a*x[0] + b) * (a*x[0] + b) - x[1]);
}
int comp()
{
double lb[2] = { -HUGE_VAL, 0 }; /* lower bounds */
nlopt_opt opt;
opt = nlopt_create(NLOPT_LD_MMA, 2); /* algorithm and dimensionality */
nlopt_set_lower_bounds(opt, lb);
nlopt_set_min_objective(opt, myfunc, NULL);
my_constraint_data data[2] = { {2,0}, {-1,1} };
nlopt_add_inequality_constraint(opt, myconstraint, &data[0], 1e-8);
nlopt_add_inequality_constraint(opt, myconstraint, &data[1], 1e-8);
nlopt_set_xtol_rel(opt, 1e-4);
double x[2] = { 1.234, 5.678 }; /* some initial guess */
double minf; /* the minimum objective value, upon return */
int a=nlopt_optimize(opt, x, &minf) ;
return 1;
}
}
It optimizes simple nonlinear constrained minimization problem. The problem arises when I try to use this namespace in windows form application. I am constantly getting unhandled exception in myfunc which sees "x" as empty pointer for some reason and therefore causes error when trying to access its location. I believe that the problem is somehow caused by the fact that windows forms uses CLR but I dont know if it is solvable or not. I am using visual studio 2008 and the test programs are simple console project (which works fine) and windows forms project (that causes aforementioned errors).
My test code is based on tutorial for C from the provided link. I although tried C++ version which once again works fine in console application but gives debug assertion failed error in windows forms application.
So I guess my questions is : I have working windows forms application and I would like to use NLOpt. Is there a way to make this work ?

Unmanaged C++ Unit testing in Visual Studio 2008

I want to create a managed C++ unit test project to test an unmanaged MFC project. I have read msujaws's procedural and followed it. I implemented a test method to test the return string of a function like so:
#include "stdafx.h"
#include "TxStats.h"
#include <cstdlib>
#include <atlstr.h>
#pragma managed
#using <mscorlib.dll>
#using <System.dll>
#using <system.data.dll>
using namespace std;
using namespace System;
using namespace System::Text;
using namespace System::Text::RegularExpressions;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;
using namespace Microsoft::VisualStudio::TestTools::UnitTesting;
namespace AUnitTest
{
[TestClass]
public ref class TxStatsTest
{
private:
TestContext^ testContextInstance;
public:
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
property Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ TestContext
{
Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ get()
{
return testContextInstance;
}
System::Void set(Microsoft::VisualStudio::TestTools::UnitTesting::TestContext^ value)
{
testContextInstance = value;
}
};
#pragma region Additional test attributes
//
//You can use the following additional attributes as you write your tests:
//
//Use ClassInitialize to run code before running the first test in the class
//[ClassInitialize()]
//static void MyClassInitialize(TestContext^ testContext) {};
//
//Use ClassCleanup to run code after all tests in a class have run
//[ClassCleanup()]
//static void MyClassCleanup() {};
//
//Use TestInitialize to run code before running each test
//[TestInitialize()]
//void MyTestInitialize() {};
//
//Use TestCleanup to run code after each test has run
//[TestCleanup()]
//void MyTestCleanup() {};
//
#pragma endregion
[TestMethod]
void TestGetTxRateStr()
{
/* str to CString
CManagedClass* pCManagedClass = new CManagedClass();
pCManagedClass->ShowMessage(strMessage);
char* szMessage = (char*)Marshal::StringToHGlobalAnsi(strMessage);
CUnmanagedClass cUnmanagedClass; cUnmanagedClass.ShowMessageBox(szMessage);
Marshal::FreeHGlobal((int)szMessage);
*/
CString out = TxStats::GetTxRateStr(1024);
// convert between MFC and .NET String implementations
String ^ myManagedString = Marshal::PtrToStringAnsi((IntPtr) (char *) out.GetBuffer());
String ^ ret = myManagedString ;///gcnew String( );
Regex ^ matStr = gcnew Regex("1024 KB/s");
StringAssert::Matches(ret, matStr);
}
};
}
That tests the code in a DIFFERENT project that looks like this:
#include "stdafx.h"
#include "TxStats.h"
TxStats::TxStats()
{
}
/*
This method returns a data rate string formatted in either Bytes, KBytes, MBytes or GBytes per sec
from an int of the bytes per second.
*/
CString TxStats::GetTxRateStr(__int64 Bps)
{
enum DataUnits dunit;
const __int64 dataSizes[]= { 0x1, // 2 ^ 0
0x400, // 2 ^ 10
0x100000, // 2 ^ 20
0x40000000};// 2 ^ 30
const char *dataStrs[] = { "B/s",
"KB/s",
"MB/s",
"GB/s"};
CString out;
double datarate;
bool finish = false;
for ( dunit = A_KBYTE; dunit <= LARGER_THAN_BIGGEST_UNIT; dunit = DataUnits(dunit+1) )
{
if ( dunit == LARGER_THAN_BIGGEST_UNIT )
{
if (dataSizes[dunit - 1] <= Bps )
{
//Gigabytes / sec
datarate = Bps / ((double) dataSizes[dunit - 1]);
out.Format("%4.2f %s", datarate, dataStrs[dunit - 1]);
finish = true;
break;
}
}
else
{
if (Bps < dataSizes[dunit])
{
//(Kilo, Mega)bytes / sec
datarate = Bps / ((double) dataSizes[dunit - 1]);
out.Format("%4.2f %s", datarate, dataStrs[dunit - 1]);
finish = true;
break;
}
}
}
if (! finish)
{
out.Format("%s", "Unknown!");
}
return out.GetBuffer();
}
void TxStats::BytesToSizeStr(__int64 bytes, CString &out)
{
if (bytes < 0)
{
out = "Err";
}
else if (bytes == 0)
{
out = "0B";
}
else
{
CString size;
CString byteChar = "B";
CString unit;
int val;
if (bytes < 1024)
{
//Bytes
unit = "";
val = (int)bytes;
}
else if ( (bytes >> 10) < 1024 )
{
//Kilobytes
unit = "K";
__int64 div = 1 << 10;
val = (int) (bytes / ((double) div ));
}
else if ( (bytes >> 20) < 1024 )
{
//Megabytes
unit = "M";
__int64 div = 1 << 20;
val = (int) (bytes / ((double) div ));
}
else
{
//Else assume gigabytes
unit = "G";
__int64 div = 1 << 30;
val = (int) (bytes / ((double) div ));
}
unit = unit + byteChar;
const char * unitCharBuf = unit.GetBuffer();
size.Format("%d%s", ((int) val), unitCharBuf);
out = size.GetBuffer();
}
}
However, when I compile this code I get the following error:
2>TxStatsTest.obj : error LNK2028: unresolved token (0A0005D4) "public: static class ATL::CStringT<char,class StrTraitMFC_DLL<char,class ATL::ChTraitsCRT<char> > > __cdecl TxStats::GetTxRateStr(__int64)" (?GetTxRateStr#TxStats##$$FSA?AV?$CStringT#DV?$StrTraitMFC_DLL#DV?$ChTraitsCRT#D#ATL#####ATL##_J#Z) referenced in function "public: void __clrcall AUnitTest::TxStatsTest::TestGetTxRateStr(void)" (?TestGetTxRateStr#TxStatsTest#AUnitTest##$$FQ$AAMXXZ)
2>TxStatsTest.obj : error LNK2019: unresolved external symbol "public: static class ATL::CStringT<char,class StrTraitMFC_DLL<char,class ATL::ChTraitsCRT<char> > > __cdecl TxStats::GetTxRateStr(__int64)" (?GetTxRateStr#TxStats##$$FSA?AV?$CStringT#DV?$StrTraitMFC_DLL#DV?$ChTraitsCRT#D#ATL#####ATL##_J#Z) referenced in function "public: void __clrcall AUnitTest::TxStatsTest::TestGetTxRateStr(void)" (?TestGetTxRateStr#TxStatsTest#AUnitTest##$$FQ$AAMXXZ)
2>\trunk\<proj>\Debug\AUnitTest.dll : fatal error LNK1120: 2 unresolved externals
2>Caching metadata information for c:\program files\microsoft visual studio 9.0\common7\ide\publicassemblies\microsoft.visualstudio.qualitytools.unittestframework.dll...
2>Build log was saved at "file://trunk\<proj>\AUnitTest\Debug\BuildLog.htm"
2>AUnitTest - 3 error(s), 0 warning(s)
========== Rebuild All: 1 succeeded, 1 failed, 0 skipped ==========
Can anyone suggest why the Unit test project might not be linking against the obj files of the main project? (I have already specified the main project as a dependency of the unit test project)
You can add
#pragma comment(lib, "TxStats.lib")
to your unit test project's stdafx.cpp to link against the other library.
You need to add the *.obj files of the project you want to test to the linker inputs of the unit test project