I am writing a cross-platform compatible function in C++ that creates directories based on input filenames. I need to know if the machine is Linux or windows and use the appropriate forward or back slash. For the following code below, if the machine is Linux then isLinux = true. How do I determine the OS?
bool isLinux;
std::string slash;
std::string directoryName;
if isLinux
slash = "/";
else
slash = "\\";
end
boost::filesystem::create_directory (full_path.native_directory_string() + slash + directoryName);
Use:
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
static const std::string slash="\\";
#else
static const std::string slash="/";
#endif
BTW, you can still safely use this slash "/" on Windows as windows understands this perfectly. So just sticking with "/" slash would solve problems for all OSes even like OpenVMS where path is foo:[bar.bee]test.ext can be represented as /foo/bar/bee/test.ext.
Generally speaking, you'd have do do this with conditional compilation.
That said, if you're using boost::filesystem you should be using the portable generic path format so that you can forget about things like this.
By default, Visual Studio #defines _WIN32 in the preprocessor project settings.
So you can use
// _WIN32 = we're in windows
#ifdef _WIN32
// Windows
#else
// Not windows
#endif
Look into http://en.wikipedia.org/wiki/Uname
If you are using g++ as your compiler/GNU then you could try the code below. POSIX compliant environments support this:
#include <stdio.h>
#include <sys/utsname.h>
#include <stdlib.h>
int main()
{
struct utsname sysinfo;
if(uname(&sysinfo)) exit(9);
printf("os name: %s\n", sysinfo.sysname);
return 0;
}
One of the most used methods to do this is with a pre-processor directive. The link is for C but they're used the same way in C++. Fair warning, each compiler & OS can have their own set of directives.
predef.sourceforge.net is a comprehensive collection of all kinds of MACROs that identify compilers/operating systems and more. (linking directly to the operating system sub-site)
Related
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
I am using dirent.h 1.20 (source) for windows in VC2013.
I can't find mkdir() in it.
How am I supposed to use it? Or can I create a directory somehow only using dirent.h?
simplest way that helped without using any other library is.
#if defined _MSC_VER
#include <direct.h>
#elif defined __GNUC__
#include <sys/types.h>
#include <sys/stat.h>
#endif
void createDir(string dir) {
#if defined _MSC_VER
_mkdir(dir.data());
#elif defined __GNUC__
mkdir(dir.data(), 0777);
#endif
}
Update: Since C++17, <filesystem> is the portable way to go. For earlier compilers, check out Boost.Filesystem.
The header you are linking to is effectively turning your (POSIX) dirent.h calls into (native) Windows calls. But dirent.h is about directory entries, i.e. reading directories, not creating ones.
If you want to create a directory (mkdir()), you need either:
A similar wrapping header turning your (POSIX) mkdir() call into the corresponding (native) Windows function calls (and I cannot point out such a header for you), or
use the Windows API directly, which might be pragmatic but would lead to a really ugly mix of POSIX and Windows functions...
// UGLY - these two don't belong in the same source...
#include <dirent.h>
#include <windows.h>
// ...
CreateDirectory( "D:\\TestDir", NULL );
// ...
Another solution would be to take a look at Cygwin, which provides a POSIX environment running on Windows, including Bash shell, GCC compiler toolchain, and a complete collection of POSIX headers like dirent.h, sys/stat.h, sys/types.h etc., allowing you to use the POSIX API consistently in your programming.
Visual Studio includes the <direct.h> header.
This header declares _mkdir and _wmkdir, which can be used to create a directory, and are part of the C libraries included with Visual Studio.
The other "easy" option would be to use Windows API calls as indicated by DevSolar.
You can use sys/types.h header file and use
mkdir(const char*) method to create a directory
Following is the sample code
#include<stdio.h>
#include<string.h>
#include <unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
int main()
{
if(!mkdir("C:mydir"))
{
printf("File created\n");
}
else
printf("Error\n");
}
mkdir is deprecated. Give #include <direct.h> as a header file. then write
_mkdir("C:/folder")
I'm using Visual C++ to build and test a project, but I'll also be using it on other platforms. I started the code initially on a different platform.
In some of my class headers I need to include a file which is specific to the other platform, however, this file doesn't exist in the Visual C++ workspace.
I've tried using code like this:
#if TARGET == OTHERPLATFORM
#include "themissingfile.h"
#endif
where TARGET is defined elsewhere as WINDOWS
#define TARGET WINDOWS
However, I still get a compiler error stating that "themissingfile.h" cannot be found. It appears like the precompiler is processing the include before the if. What's the best way to get around this? I suppose I could just create a blank "themissingfile.h" in the Visual C++ source folder, but it seems to me like there should be a better solution.
#define TARGET WINDOWS does not set TARGET to the string WINDOWS: it sets it to whatever WINDOWS is defined to. Most likely this happens:
#define WINDOWS // Sets WINDOWS to 0
#define OTHERPLATFORM // Sets OTHERPLATFORM to 0
#define TARGET WINDOWS // Sets TARGET to 0
#if TARGET == OTHERPLATFORM // Evaluates to 0==0, so true
Use _WIN32 macro instead:
#ifndef _WIN32
#include "themissingfile.h"
#endif
_WIN32 is defined for both 32-bit and 64-bit builds. See C/C++ Predefined Macros.
I have a problem while porting a Linux tool to Windows. I am using MinGW on a Windows system. I have a class which handles all the in/output and within is this line:
mkdir(strPath.c_str(), 0777); // works on Linux but not on Windows and when it is changed to
_mkdir(strPath.c_str()); // it works on Windows but not on Linux
Any ideas what I can do, so that it works on both systems?
#if defined(_WIN32)
_mkdir(strPath.c_str());
#else
mkdir(strPath.c_str(), 0777); // notice that 777 is different than 0777
#endif
You should be able to use conditional compilation to use the version that applies to the OS you are compiling for.
Also, are you really sure you want to set the flags to 777 (as in wide open, please deposit your virus here)?
You can conditionally compile with some preprocessor directives, a pretty complete list of which you can find here: C/C++ Compiler Predefined Macros
#if defined(_WIN32)
_mkdir(strPath.c_str());
#elif defined(__linux__)
mkdir(strPath.c_str(), 0777);
// #else more?
#endif
So jenerally I have small C++ project based on OpenSource crossplatform libs. So it probably would compile under linux. So I hited the point when I need to implement some defenatly platform specific class functions.
I have a class header with all functions declarations and cpp file with realisations. So first: how to declare my platform specific functions in header so when I'll try to compile under linux it will not try to compile windows specific ones... and when on windows compiler will not try to compile linux functions include headers etc.
So for windows I need some how wrap such super specific functions
HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
void DisplayDeviceInformation(IEnumMoniker *pEnum)
And some headers
#include <windows.h>
#include <dshow.h>
#pragma comment(lib, "strmiids")
While for linux I have such headers
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/videodev.h>
And I have function with name of void PrintCamerasList() which I wanna have one for bouth platfrms realisations for which I have seprate.
I hope you see what I need. So generally I need some example using my functions or once you can invent - let your imagination flow!)
So why do I need it all - I am creating some console app using OpenCV and I need to list user cameras names. OpenCV cannot do this on its own. so I asked how to do it for bouth platforms of my intrest - windows and linux
You want to look into platform specific macros and surround for example your MSVC specific code with some #ifdef _WIN32 / #endif pairs.
Take a look at http://predef.sourceforge.net/ for an extensive list of pre-defined macros various compilers provide to distinguish between operating systems, compilers, and processor architectures. They will allow you to distinguish between more than just Win32 and Linux if necessary.
Common practice is to use a compiler flag such as
#ifdef WIN_32
// Windows stuff...
#else
// Linux stuff
#endif
Check for the exact values of what windows flag is defined either in your compiler or in the headers you include