Search for avaliable library before #pragma comment in c++? - c++

I have a piece of code which relies on the "Xinput.lib" file provided by windows in order to interface with a xbox controller.
Recently I installed VS2012 which seems to have caused "Xinput.lib" to no longer be available to the compiler. I found a workaround where I instead I use "Xinput9_1_0.lib" on the system running the VS2012 compiler. This however causes a problem since I am developing on multiple systems where one is running VS2012 and the other is running VS2010. To compile I have to change between "Xinput9_1_0.lib" and "Xinput.lib" within the code.
What I am wondering is if there is a way to search for the available library before using #pragma comment to link the library?
Something like this (I realize this is in no way valid, just a demonstration of intent):
if("Xinput.lib" exists) {
#pragma comment(lib,"Xinput.lib")
}
else if("Xinput9_1_0.lib" exists) {
#pragma comment(lib,"Xinput9_1_0.lib")
}

Use the macro for the particular version of VS you're interested in:
#ifdef MSC_VER < 1700 //pre 2012
#pragma comment(lib,"Xinput.lib")
#else
#pragma comment(lib,"Xinput9_1_0.lib")
#endif

Related

OpenCASCADE 7.6.0 not compiling with a .NET 6.0 class library with Visual Studio 2022 (Windows 10)

Steps to reproduce:
Install a version of Visual Studio (I used VS Community 2022). Install OpenCASCADE 7.6.0.
Create a C++ .NET CLR project using Visual Studio 2022 targeting .net6.0.
Change settings to include OpenCASCADE header and library files.
Edit the main header by replacing the code within it with below:
#pragma once
//for OCC graphic
#include <OpenGl_GraphicDriver.hxx>
//wrapper of pure C++ classes to ref classes
#include <NCollection_Haft.h>
namespace ClrClsLibDotNetCoreMwe {
public ref class Class1
{
// TODO: Add your methods for this class here.
};
}
Attempt to build.
Issue: The build fails with the following complain:
1>C:\OpenCASCADE-7.6.0-vc14-64\opencascade-7.6.0\inc\NCollection_DefaultHasher.hxx(34,1): error C2872: 'HashCode': ambiguous symbol
1>C:\OpenCASCADE-7.6.0-vc14-64\opencascade-7.6.0\inc\NCollection_DefaultHasher.hxx(34,1): message : could be 'HashCode'
1>C:\OpenCASCADE-7.6.0-vc14-64\opencascade-7.6.0\inc\NCollection_DefaultHasher.hxx(34,1): message : or 'System::HashCode'
What fixes the problem:
Either Targeting .NET Framework instead of .NET Core (/clr instead of /clr:netcore).
Or removing one of the headers.
Please see if there is a way where I can keep both the headers and target .NET Core?
I have looked around for a possible solution before posting this question here. A promising solution was to disable implicit usings. However, that didn't pan out.
I had the same problem.
In my case, the "using namespace System;" included in the header file. The text caused the problem.
Thanks!

How do is structure my files right, when I write code for linux and windows

I am currently not sure how I should seperate my code best. I currently programming a software which should run on Linux and Windows. So I decided to put all OS-secificstuff in thier own folder/files.
For example
This is the header file:
#ifdef __linux__
#include <unistd.h>
#elif _WIN64
#include <Windows.h>
#endif
#include <string>
#include <iostream>
#pragma once
class SystemTools
{
public:
// Delay in secounds until the programm continues
static void sleep(int delay);
private:
};
and the OS specific implementation is in the linux/windows folder
Linux:
#ifdef __linux__
#include "../SystemTools.h"
void SystemTools::sleep(int delay)
{
usleep(delay*1000000);
}
#endif
Windows:
#ifdef _WIN64
#include "../SystemTools.h"
void SystemTools::sleep(int delay)
{
Sleep(delay*1000);
}
#endif
This works and I have no problems so far, but when I now have methods which don´t need any OS specific code I created an additional folder "Generic" so I can write the code in there and don´t have to mantain the same code in the linux and windows file. For example like that:
Generic:
#include "../SystemTools.h"
void SystemTools::sleepMin(int delay)
{
sleep(delay*60);
}
#endif
That still workes on Linux but not on Windows (no error but does not compile, used codeblockes for that on windows). So how do I organize my code correct? Should I use only one file with ifdef even it that gets very fast ugly?
(compiler Linux: g++, Windows: should be MinGW)
Firstly I'd suggest you to use the most recent of C++ (C++20 or so) on your project. This way, we can abstract many OS related calls (like threading, synchronization, random numbers and etc).
That means, you won't really need to use too many of OS specific APIs. IE: C++11 and earlier already have a standard way to sleep:
https://en.cppreference.com/w/cpp/thread/sleep_for
In the end, if you really need to call OS specific things on windows and on linux, using a library could be interesting and pay attention that windows C++ compiler (visual studio) really like to use 'pre compiled headers' so, it's interesting to have a single header file where all windows specific headers can be included.
Basically that. You can have a standard Cmake or makefile for your linux build and use .sln Visual Studio project to build it to windows.
That's the way I would do that

TBB on Windows XP (using in OpenCV) - error entry point InitializeCriticalSectionEx

I tried to compile TBB which I want to use on OpenCV. I am using Windows XP and Visual Studio 2010 C++. When I compiled TBB 4.4 I got the error
"The procedure entry point InitializeCriticalSectionEx could not be located in the dynamic link library KERNEL32.dll."
The error is similar but under little different conditions like here:
http://answers.opencv.org/question/6151/opencv_createsamplesexe-entry-point-problem-with-xp/
In my case I cannot run the program at all. I tried the solution described there, so I renamed InitializeCriticalSectionEx to InitializeCriticalSection and removed parameter 2 and 3.
OpenCV claimes the bug is not on their side. I know OpenCV uses this:
#if (_WIN32_WINNT >= 0x0600)
InitializeCriticalSectionEx(&cs, 1000, 0);
#else
InitializeCriticalSection(&cs);
#endif
I know this should not make any problems but I commented some lines to keep InitializeCriticalSection(&cs); only. I recompiled the OpenCV and still the same error. Finally I have found in TTB:
tbb44_20160627oss\include\tbb\machine\windows_api.h
__TBB_WINBASEAPI BOOL WINAPI TryEnterCriticalSection( LPCRITICAL_SECTION );
__TBB_WINBASEAPI BOOL WINAPI InitializeCriticalSectionAndSpinCount( LPCRITICAL_SECTION, DWORD );
// Overloading WINBASEAPI macro and using local functions missing in Windows XP/2003
#define InitializeCriticalSectionEx inlineInitializeCriticalSectionEx
I also find the word "InitializeCriticalSectionEx" in opencv_core310d.dll and opencv_core310.dll. Does the overload really work and why I got the error? How could I fix it?
Update:
the definition in OpenCV
#ifndef _WIN32_WINNT // This is needed for the declaration of TryEnterCriticalSection in winbase.h with Visual Studio 2005 (and older?)
#define _WIN32_WINNT 0x0400 // http://msdn.microsoft.com/en-us/library/ms686857(VS.85).aspx
#endif
"The procedure entry point InitializeCriticalSectionEx could not be located in the dynamic link library KERNEL32.dll."
This is a standard error that Windows displays when you try to run a program that contains a statically-bound call to a function in a DLL that does not exist.
The InitializeCriticalSectionEx function is not available on Windows XP, but the version of the library that you have contains code that calls this function.
OpenCV claimes the bug is not on their side. I know OpenCV uses this:
#if (_WIN32_WINNT >= 0x0600)
InitializeCriticalSectionEx(&cs, 1000, 0);
#else
InitializeCriticalSection(&cs);
#endif
OpenCV's workaround is a compile-time solution. It determines at the point when the library is compiled which version of Windows is being targeted, and uses that information to generate a call to the appropriate version of the function.
There are two possibilities for why this is going wrong in your case:
You are using the OpenCV library in binary form, and the binary that you have was compiled to target Windows Vista and later. You can solve this by obtaining the source code for OpenCV and compiling it yourself, either as a DLL or a static library.
You are compiling with _WIN32_WINNT set to 0x0600 or later. By default, the Windows headers define this symbol to the latest available version. You have to explicitly define an earlier target version if you want it. To arrange for targeting Windows XP, add the following code at the top of your code file (probably in your precompiled header):
#include <WinSDKVer.h>
#define _WIN32_WINNT _WIN32_WINNT_WINXP
#include <SDKDDKVer.h>

boost.future causing problems with clr

I am using visual studio 2012 with a clr library that needs to link to a native library.
My library which is using boost::future.
I am having this problem when I use future::then(F &&) function against the managed project:
Error 910 error LNK2022: metadata operation failed (8013119F) : A TypeRef exists which should, but does not, have a corresponding TypeDef: (dummy): (0x0100003e). D:\ClrProject\somefile.obj
I tried, as suggested in other questions, to make the dummy types in the library complete, since I cannot forward declare a nested struct from inside a template, as can be done with boost::thread::dummy struct.
This did not solve the problem.
My setup is the following:
Boost 1.55.
Using boost .dlls.
define BOOST_RESULT_OF_USE_DECLTYPE
define BOOST_THREAD_PROVIDES_FUTURE
define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
I am using these very defines on the dependent .dll as well, to make sure that all parts of the API are exposed correctly.
Solved.
#Hans Passant your suggestion was right. I just wasn't putting the #pragma the correct way.
I had to put the pragmas so that my headers are compiled as unmanaged code. Once that was done, it seems that template instantiations for my code were emitted as unmanaged. At that point, problems disappeared.
So what I did is something like this:
#pragma managed(push, off)
#include "MyHeaderWithFutures.h"
#pragma managed(pop)
void f() {
//
f = myObject.Something().then(...);
}

Automatically Including OpenCV Libraries of Different Versions

I've been automatically including the opencv library files for my c++ code on Visual Studio 2008 on Windows 7 with the following code:
#ifndef NDEBUG
#pragma comment(lib, "opencv_core231d.lib")
#pragma comment(lib, "opencv_highgui231d.lib")
#pragma comment(lib, "opencv_imgproc231d.lib")
#else
#pragma comment(lib, "opencv_core231.lib")
#pragma comment(lib, "opencv_highgui231.lib")
#pragma comment(lib, "opencv_imgproc231.lib")
#endif
but I run into trouble when the system has a different version of the opencv library installed because the .lib files have the version (in this case, 2.31) in the filename. Is there a good way to automatically or near-automatically detect what version of the opencv library is available then slide in the appropriate version string into the pragma?
There are small changes between different OpenCV versions - not much, but enough to crash your app when you change from 2.0 to 2.2 or from 2.2 to 2.3.1. Also, the beta 2.4 release has enough changes from previous ones.
So best is to test your app with an OpenCV version, and deliver it with those dlls only.
A small example:
Mat a(3,3,CV_8UC3);
a.setTo( Scalar(10) ); // in 2.3.1 will set all channels to 10,
// in 2.2 will only set first channel.
The corresponding 2.2 call would be
a.setTo(Scalar::all(10));
Or
a = 0; // runs fine on 2.3.1. Equivalent to setTo().
// Does not compile on earlier versions
Another example is cv::drawPoly(), which has a different signature on 2.2 and 2.3.1.
Given the fact that those changes are not well documented, the chance to miss one of them by mistake is really high.
I have worked out a solution to having code run on various versions of OPENCV by merging the following articles:
How to make a string out of macros
Concatenating strings in macros
Pragma statements in #defines with support for VS2008 here on MSDN
Bonus: How to have global settings defined in a solution
As noted, this can cause some serious grief if you pop between incompatible versions but for those versions and features supported this may be useful to some. Use this technique to set the opencv version once and have your code automatically link to the desired version by either
define the OPENCV_VERSIONin one place in your source code
Define it in a Property Sheet
Define it in a system environment variable.
My code ended up like so:
#include <iostream>
// #define OPENCV_VERSION $(OPENCV_VERSION)
// #define OPENCV_VERSION 220
#define QUOTE(name) #name
#define STR(macro) QUOTE(macro)
#define LINK_TO_OPENCV(libname) __pragma(comment(lib, "opencv_" #libname STR(OPENCV_VERSION)))
#define LINK_TO_OPENCV_DEBUG(libname) __pragma(comment(lib, "opencv_" #libname STR(OPENCV_VERSION) "d"))
#ifndef NDEBUG
LINK_TO_OPENCV_DEBUG("core")
LINK_TO_OPENCV_DEBUG("highgui")
LINK_TO_OPENCV_DEBUG("imgproc")
#else
LINK_TO_OPENCV("core")
LINK_TO_OPENCV("highgui")
LINK_TO_OPENCV("imgproc")
#endif
int main()
{
std::cout << STR(LINK_TO_OPENCV("core")) << "\n";
return 0;
}
And now to set the OPENCV_VERSION anywhere you like. For example, you can have a single header file included by everyone that has the line:
#define OPENCV_VERSION 220
Or you can goto Project->Properties->C/C++->Preprocessor and set Preprocessor Definitions to OPENCV_VERSION=220. Or you can do the same thing in a shared property sheet for the entire solution.
Or, and this is important, you can use this technique to define a global environment variable in windows itself called OPENCV_VERSION_ENV and set its value to the version code (say, 220). Then you can put set the preprocessor definition to OPENCV_VERSION=$(OPENCV_VERSION_ENV) and you will bring in the environment variable into the link command. You CANNOT do a #define OPEN_VERSION $(OPENCV_VERSION_ENV) but since the property pages will automatically translate $(macros) we can get environment variables there.