How to determine the platform Qt is running on at runtime? - qt

Is there a (Qt) way to determine the platform a Qt application is running on at runtime?

Intention: While I hate to bring up a question
that is almost 2 years old, I think
that a good amended answer is valuable
to have on record so that others that
end up on this question can do it the
right way.
I can't help but notice that most of the answers recommend using the Q_WS set of macros to determine the Operating System, this is not a good solution, since Q_WS_* refers to the Windowing System and not the Operating System platform(for eg. X11 can be run on Windows or Mac OS X then what?), thus one should not follow those macros to determine the platform for which the application has been compiled.
Instead one should use the Q_OS_* set of macros which have the precise purpose of determining the Operating System.
The set currently consists of the following macros for Qt 4.8:
Q_OS_AIX
Q_OS_BSD4
Q_OS_BSDI
Q_OS_CYGWIN
Q_OS_DARWIN
Q_OS_DGUX
Q_OS_DYNIX
Q_OS_FREEBSD
Q_OS_HPUX
Q_OS_HURD
Q_OS_IRIX
Q_OS_LINUX
Q_OS_LYNX
Q_OS_MAC
Q_OS_MSDOS
Q_OS_NETBSD
Q_OS_OS2
Q_OS_OPENBSD
Q_OS_OS2EMX
Q_OS_OSF
Q_OS_QNX
Q_OS_RELIANT
Q_OS_SCO
Q_OS_SOLARIS
Q_OS_SYMBIAN
Q_OS_ULTRIX
Q_OS_UNIX
Q_OS_UNIXWARE
Q_OS_WIN32
Q_OS_WINCE
References:
Qt 4 https://doc.qt.io/archives/qt-4.8/qtglobal.html
Qt 5 https://doc.qt.io/qt-5/qtglobal.html
Qt 6 https://doc.qt.io/qt-6/qtglobal.html
NB: As mentioned by Wiz in the comments, Qt 5 completely removed the Q_WS_* set of macros, thus now all you can use are Q_OS_* ones.

Note that the Q_WS_* macros are defined at compile time, but QSysInfo gives some run time details.
To extend gs's function to get the specific windows version at runtime, you can do
#ifdef Q_WS_WIN
switch(QSysInfo::windowsVersion())
{
case QSysInfo::WV_2000: return "Windows 2000";
case QSysInfo::WV_XP: return "Windows XP";
case QSysInfo::WV_VISTA: return "Windows Vista";
default: return "Windows";
}
#endif
and similar for Mac.
If you are using a Qt version 5.9 or above, kindly use the below mentioned library function to retrieve correct OS details, more on this can be found here. There is also a QSysInfo class which can do some additional functionalities.
#ifdef Q_WS_WIN
#include <QOperatingSystemVersion>
switch(QOperatingSystemVersion::current())
{
case QOperatingSystemVersion::Windows7: return "Windows 7";
case QOperatingSystemVersion::Windows8: return "Windows 8";
case QOperatingSystemVersion::Windows10: return "Windows 10";
default: return "Windows";
}
#endif

For Qt5 I use the following:
logging.info("##### System Information #####")
sysinfo = QtCore.QSysInfo()
logging.info("buildCpuArchitecture: " + sysinfo.buildCpuArchitecture())
logging.info("currentCpuArchitecture: " + sysinfo.currentCpuArchitecture())
logging.info("kernel type and version: " + sysinfo.kernelType() + " " + sysinfo.kernelVersion())
logging.info("product name and version: " + sysinfo.prettyProductName())
logging.info("#####")
Documentation: http://doc.qt.io/qt-5/qsysinfo.html

Here is part of my code to detect windows or mac at run time and the version
#include <QSysInfo>
#include <QOperatingSystemVersion>
auto OSType= OSInfo.type();
auto OSInfo = QOperatingSystemVersion::current();
if (OSType !=1) //not windows os
{
return 0;
}
if (OSInfo < QOperatingSystemVersion::Windows7) // less than win7
{
return 0;
}

Related

DateTime.ToString in Mono return invalid date ("00/734718/0001 01:41:38")

I am trying to get mono (Debian 2.10.8.1-5) to run properly on my raspberry pi with the raspbian distro ("Debian GNU/Linux wheezy/sid"). I have installed mono with apt-get install mono-complete.
However, I am running into an interesting issue that I cannot figure out. The DateTime.ToString() method returns an invalid string.
Below you can find my sample program with the console output:
using System;
namespace MonoTest
{
class Program
{
static void Main(string[] args)
{
DateTime now = DateTime.Now;
Console.WriteLine("Year: " + now.Year);
Console.WriteLine("Month: " + now.Month);
Console.WriteLine("Day: " + now.Day);
Console.WriteLine("DayOfWeek: " + now.DayOfWeek);
Console.WriteLine("DateTime.Now: " + DateTime.Now);
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd"));
}
}
}
Output:
pi#raspberrypi ~/bin $ mono MonoTest.exe
Year: 2012
Month: 8
Day: 3
DayOfWeek: Friday
DateTime.Now: 00/734718/0001 01:41:38
0001-00-734718
Interestingly enough, 734718 seems to be the the number of days elapsed till today since 01/01/0001. I have tryed it with a fresh installation on a second board but with the same issue.
Does anyone have an idea what the problem here is and how to convince DateTime.ToString() to return the right value?
Update (8/4/2012): After long digging through the mono source code I was able to trace the issue back to System.Math.Floor. Apparently, it always returns 0. I changed my test program to a simple:
static void Main(string[] args)
{
Console.WriteLine("Floor(1.5): " + System.Math.Floor(1.5));
}
On Windows the result is "Floor(1.5): 1" Whereas on my mono setup on the raspberry pi is "Floor(1.5): 0". I have seen that System.Math.Floor is implemented as
[MethodImplAttribute (MethodImplOptions.InternalCall)]
public extern static double Floor (double d);
Tomorrow, I will look further into this issue. Does anyone know why this issue could exist?
This is Mono bug #7938, and it affects not just DateTime.ToString, but ANY function that, directly or indirectly, passes a floating-point number to a library call, when running on ARM with a Linux distro built for the hard-float ABI. More details are available at the C# on Raspberry Pi wiki page. There is currently no good fix for this, short of running a soft-float distro. I'm still hoping we can get a fixed mono runtime soon.
I can't reproduce your issue on Windows (don't have raspberry, but your subject says Mono).
I copied and pasted your exact source for Main() into a new Mono console app (Mono 2.6.1), added a single line (Console.ReadLine();), and ran it:
using System;
namespace TestDateTimeNow
{
class MainClass
{
public static void Main (string[] args)
{
DateTime now = DateTime.Now;
Console.WriteLine("Year: " + now.Year);
Console.WriteLine("Month: " + now.Month);
Console.WriteLine("Day: " + now.Day);
Console.WriteLine("DayOfWeek: " + now.DayOfWeek);
Console.WriteLine("DateTime.Now: " + DateTime.Now);
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd"));
Console.ReadLine();
}
}
}
I get the output below:
That's most likely to be an ARM Mono binary layer bug. Especially since you are running a version that was release before Raspberry Pi. You will have much better luck with that on mono-devel mailing list. And it's possible that this is fixed in git already.
You need to use the soft floating point OS for this. 2013-05-29-wheezy-armel.zip for example.
The hard floating point doesn't work well with JITers. I had the same issue, resolved it by installing the soft floating point version of the OS on my RP. I wouldn't recommended using .net with a hard floating point OS under the raspberry pi platform. Hope this helps.

What API does Qt use for interacting with the Windows clipboard?

I've been browsing the Qt source code trying to find the actual system calls but it seems Qt doesn't use the Windows API documented on MSDN. For example grepping the source for "GetClipboardData" returns results in two files:
qclipboard_win.cpp:
#if defined(Q_OS_WINCE)
...
HANDLE clipData = GetClipboardData(CF_TEXT)
qaxserverbase.cpp:
STDMETHOD(GetClipboardData)(DWORD dwReserved, IDataObject** ppDataObject);
...
HRESULT WINAPI QAxServerBase::GetClipboardData(DWORD, IDataObject**)
{
return E_NOTIMPL;
}
and "SetClipboardData":
qclipboard_win.cpp:
#if defined(Q_OS_WINCE)
...
result = SetClipboardData(CF_UNICODETEXT, wcsdup(reinterpret_cast<const wchar_t *> (data->text().utf16()))) != NULL;
Neither of which seems useful, since they're being declared for Win CE/Mobile.
My Qt (4.8.1) uses OleSetClipboard and OleGetClipboard. The lines you got to are never reached in regular windows, as only in case of #if defined(Q_OS_WINCE) Qt uses #define OleSetClipboard QtCeSetClipboard and #define OleGetClipboard QtCeGetClipboard, and otherwise uses system-provided versions of those functions.
It was a little dificult to see this #if defined though, so you are excused ;)
It is so at least on my Qt version. If you are talking about qt, and especially about it's internals, you should menstion the version, right?

Getting memory information with Qt

How can I obtain this information:
Total Memory
Free Memory
Memory used by current running application ?
I think Qt should have memory options, that would be platform-independent, but
I can't find it. So what can I do when I want to make a platform-independent application that shows memory state?
Unfortunately, there is nothing built into Qt for this. You must do this per-platform.
Here are some samples to get you started. I had to implement this in one of my apps just last week. The code below is still very much in development; there may be errors or leaks, but it might at least point you in the correct direction. I was only interested in total physical RAM, but the other values are available in the same way. (Except perhaps memory in use by the current application ... not sure about that one.)
Windows (GlobalMemoryStatusEx)
MEMORYSTATUSEX memory_status;
ZeroMemory(&memory_status, sizeof(MEMORYSTATUSEX));
memory_status.dwLength = sizeof(MEMORYSTATUSEX);
if (GlobalMemoryStatusEx(&memory_status)) {
system_info.append(
QString("RAM: %1 MB")
.arg(memory_status.ullTotalPhys / (1024 * 1024)));
} else {
system_info.append("Unknown RAM");
}
Linux (/proc/meminfo)
QProcess p;
p.start("awk", QStringList() << "/MemTotal/ { print $2 }" << "/proc/meminfo");
p.waitForFinished();
QString memory = p.readAllStandardOutput();
system_info.append(QString("; RAM: %1 MB").arg(memory.toLong() / 1024));
p.close();
Mac (sysctl)
QProcess p;
p.start("sysctl", QStringList() << "kern.version" << "hw.physmem");
p.waitForFinished();
QString system_info = p.readAllStandardOutput();
p.close();
Much better on POSIX OSes (Linux, Solaris, perhaps latest MacOS...) :
getrusage(...) secially look at ru_maxrss.
getrlimit(...) but I did not find any usefull info into.
sysconf(...) : _SC_PAGESIZE, _SC_PHYS_PAGES, _SC_AVPHYS_PAGES
sysinfo(...) : totalram, freeram, sharedram, totalswap,...
So much treasures on POSIX computers not available on Windows.
This is currently not possible in Qt. You would need to ifdef the different OS memory calls.

Is there a way for a C binary code to figure out where it is stored? [duplicate]

Is there a platform-agnostic and filesystem-agnostic method to obtain the full path of the directory from where a program is running using C/C++? Not to be confused with the current working directory. (Please don't suggest libraries unless they're standard ones like clib or STL.)
(If there's no platform/filesystem-agnostic method, suggestions that work in Windows and Linux for specific filesystems are welcome too.)
Here's code to get the full path to the executing app:
Variable declarations:
char pBuf[256];
size_t len = sizeof(pBuf);
Windows:
int bytes = GetModuleFileName(NULL, pBuf, len);
return bytes ? bytes : -1;
Linux:
int bytes = MIN(readlink("/proc/self/exe", pBuf, len), len - 1);
if(bytes >= 0)
pBuf[bytes] = '\0';
return bytes;
If you fetch the current directory when your program first starts, then you effectively have the directory your program was started from. Store the value in a variable and refer to it later in your program. This is distinct from the directory that holds the current executable program file. It isn't necessarily the same directory; if someone runs the program from a command prompt, then the program is being run from the command prompt's current working directory even though the program file lives elsewhere.
getcwd is a POSIX function and supported out of the box by all POSIX compliant platforms. You would not have to do anything special (apart from incliding the right headers unistd.h on Unix and direct.h on windows).
Since you are creating a C program it will link with the default c run time library which is linked to by ALL processes in the system (specially crafted exceptions avoided) and it will include this function by default. The CRT is never considered an external library because that provides the basic standard compliant interface to the OS.
On windows getcwd function has been deprecated in favour of _getcwd. I think you could use it in this fashion.
#include <stdio.h> /* defines FILENAME_MAX */
#ifdef WINDOWS
#include <direct.h>
#define GetCurrentDir _getcwd
#else
#include <unistd.h>
#define GetCurrentDir getcwd
#endif
char cCurrentPath[FILENAME_MAX];
if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
{
return errno;
}
cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */
printf ("The current working directory is %s", cCurrentPath);
This is from the cplusplus forum
On windows:
#include <string>
#include <windows.h>
std::string getexepath()
{
char result[ MAX_PATH ];
return std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) );
}
On Linux:
#include <string>
#include <limits.h>
#include <unistd.h>
std::string getexepath()
{
char result[ PATH_MAX ];
ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX );
return std::string( result, (count > 0) ? count : 0 );
}
On HP-UX:
#include <string>
#include <limits.h>
#define _PSTAT64
#include <sys/pstat.h>
#include <sys/types.h>
#include <unistd.h>
std::string getexepath()
{
char result[ PATH_MAX ];
struct pst_status ps;
if (pstat_getproc( &ps, sizeof( ps ), 0, getpid() ) < 0)
return std::string();
if (pstat_getpathname( result, PATH_MAX, &ps.pst_fid_text ) < 0)
return std::string();
return std::string( result );
}
If you want a standard way without libraries: No. The whole concept of a directory is not included in the standard.
If you agree that some (portable) dependency on a near-standard lib is okay: Use Boost's filesystem library and ask for the initial_path().
IMHO that's as close as you can get, with good karma (Boost is a well-established high quality set of libraries)
I know it is very late at the day to throw an answer at this one but I found that none of the answers were as useful to me as my own solution. A very simple way to get the path from your CWD to your bin folder is like this:
int main(int argc, char* argv[])
{
std::string argv_str(argv[0]);
std::string base = argv_str.substr(0, argv_str.find_last_of("/"));
}
You can now just use this as a base for your relative path. So for example I have this directory structure:
main
----> test
----> src
----> bin
and I want to compile my source code to bin and write a log to test I can just add this line to my code.
std::string pathToWrite = base + "/../test/test.log";
I have tried this approach on Linux using full path, alias etc. and it works just fine.
NOTE:
If you are on windows you should use a '\' as the file separator not '/'. You will have to escape this too for example:
std::string base = argv[0].substr(0, argv[0].find_last_of("\\"));
I think this should work but haven't tested, so comment would be appreciated if it works or a fix if not.
Filesystem TS is now a standard ( and supported by gcc 5.3+ and clang 3.9+ ), so you can use current_path() function from it:
std::string path = std::experimental::filesystem::current_path();
In gcc (5.3+) to include Filesystem you need to use:
#include <experimental/filesystem>
and link your code with -lstdc++fs flag.
If you want to use Filesystem with Microsoft Visual Studio, then read this.
No, there's no standard way. I believe that the C/C++ standards don't even consider the existence of directories (or other file system organizations).
On Windows the GetModuleFileName() will return the full path to the executable file of the current process when the hModule parameter is set to NULL. I can't help with Linux.
Also you should clarify whether you want the current directory or the directory that the program image/executable resides. As it stands your question is a little ambiguous on this point.
On Windows the simplest way is to use the _get_pgmptr function in stdlib.h to get a pointer to a string which represents the absolute path to the executable, including the executables name.
char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe
Maybe concatenate the current working directory with argv[0]? I'm not sure if that would work in Windows but it works in linux.
For example:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char **argv) {
char the_path[256];
getcwd(the_path, 255);
strcat(the_path, "/");
strcat(the_path, argv[0]);
printf("%s\n", the_path);
return 0;
}
When run, it outputs:
jeremy#jeremy-desktop:~/Desktop$ ./test
/home/jeremy/Desktop/./test
For Win32 GetCurrentDirectory should do the trick.
You can not use argv[0] for that purpose, usually it does contain full path to the executable, but not nessesarily - process could be created with arbitrary value in the field.
Also mind you, the current directory and the directory with the executable are two different things, so getcwd() won't help you either.
On Windows use GetModuleFileName(), on Linux read /dev/proc/procID/.. files.
Just my two cents, but doesn't the following code portably work in C++17?
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main(int argc, char* argv[])
{
std::cout << "Path is " << fs::path(argv[0]).parent_path() << '\n';
}
Seems to work for me on Linux at least.
Based on the previous idea, I now have:
std::filesystem::path prepend_exe_path(const std::string& filename, const std::string& exe_path = "");
With implementation:
fs::path prepend_exe_path(const std::string& filename, const std::string& exe_path)
{
static auto exe_parent_path = fs::path(exe_path).parent_path();
return exe_parent_path / filename;
}
And initialization trick in main():
(void) prepend_exe_path("", argv[0]);
Thanks #Sam Redway for the argv[0] idea. And of course, I understand that C++17 was not around for many years when the OP asked the question.
Just to belatedly pile on here,...
there is no standard solution, because the languages are agnostic of underlying file systems, so as others have said, the concept of a directory based file system is outside the scope of the c / c++ languages.
on top of that, you want not the current working directory, but the directory the program is running in, which must take into account how the program got to where it is - ie was it spawned as a new process via a fork, etc. To get the directory a program is running in, as the solutions have demonstrated, requires that you get that information from the process control structures of the operating system in question, which is the only authority on this question. Thus, by definition, its an OS specific solution.
#include <windows.h>
using namespace std;
// The directory path returned by native GetCurrentDirectory() no end backslash
string getCurrentDirectoryOnWindows()
{
const unsigned long maxDir = 260;
char currentDir[maxDir];
GetCurrentDirectory(maxDir, currentDir);
return string(currentDir);
}
For Windows system at console you can use system(dir) command. And console gives you information about directory and etc. Read about the dir command at cmd. But for Unix-like systems, I don't know... If this command is run, read bash command. ls does not display directory...
Example:
int main()
{
system("dir");
system("pause"); //this wait for Enter-key-press;
return 0;
}
Works with starting from C++11, using experimental filesystem, and C++14-C++17 as well using official filesystem.
application.h:
#pragma once
//
// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros
//
#ifdef __cpp_lib_filesystem
#include <filesystem>
#else
#include <experimental/filesystem>
namespace std {
namespace filesystem = experimental::filesystem;
}
#endif
std::filesystem::path getexepath();
application.cpp:
#include "application.h"
#ifdef _WIN32
#include <windows.h> //GetModuleFileNameW
#else
#include <limits.h>
#include <unistd.h> //readlink
#endif
std::filesystem::path getexepath()
{
#ifdef _WIN32
wchar_t path[MAX_PATH] = { 0 };
GetModuleFileNameW(NULL, path, MAX_PATH);
return path;
#else
char result[PATH_MAX];
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
return std::string(result, (count > 0) ? count : 0);
#endif
}
For relative paths, here's what I did. I am aware of the age of this question, I simply want to contribute a simpler answer that works in the majority of cases:
Say you have a path like this:
"path/to/file/folder"
For some reason, Linux-built executables made in eclipse work fine with this. However, windows gets very confused if given a path like this to work with!
As stated above there are several ways to get the current path to the executable, but the easiest way I find works a charm in the majority of cases is appending this to the FRONT of your path:
"./path/to/file/folder"
Just adding "./" should get you sorted! :) Then you can start loading from whatever directory you wish, so long as it is with the executable itself.
EDIT: This won't work if you try to launch the executable from code::blocks if that's the development environment being used, as for some reason, code::blocks doesn't load stuff right... :D
EDIT2: Some new things I have found is that if you specify a static path like this one in your code (Assuming Example.data is something you need to load):
"resources/Example.data"
If you then launch your app from the actual directory (or in Windows, you make a shortcut, and set the working dir to your app dir) then it will work like that.
Keep this in mind when debugging issues related to missing resource/file paths. (Especially in IDEs that set the wrong working dir when launching a build exe from the IDE)
A library solution (although I know this was not asked for).
If you happen to use Qt:
QCoreApplication::applicationDirPath()
Path to the current .exe
#include <Windows.h>
std::wstring getexepathW()
{
wchar_t result[MAX_PATH];
return std::wstring(result, GetModuleFileNameW(NULL, result, MAX_PATH));
}
std::wcout << getexepathW() << std::endl;
// -------- OR --------
std::string getexepathA()
{
char result[MAX_PATH];
return std::string(result, GetModuleFileNameA(NULL, result, MAX_PATH));
}
std::cout << getexepathA() << std::endl;
This question was asked 15 years ago, so the existing answers are now incorrect. If you're using C++17 or greater, the solution is very straightforward today:
#include <filesystem>
std::cout << std::filesystem::current_path();
See cppreference.com for more information.
On POSIX platforms, you can use getcwd().
On Windows, you may use _getcwd(), as use of getcwd() has been deprecated.
For standard libraries, if Boost were standard enough for you, I would have suggested Boost::filesystem, but they seem to have removed path normalization from the proposal. You may have to wait until TR2 becomes readily available for a fully standard solution.
Boost Filesystem's initial_path() behaves like POSIX's getcwd(), and neither does what you want by itself, but appending argv[0] to either of them should do it.
You may note that the result is not always pretty--you may get things like /foo/bar/../../baz/a.out or /foo/bar//baz/a.out, but I believe that it always results in a valid path which names the executable (note that consecutive slashes in a path are collapsed to one).
I previously wrote a solution using envp (the third argument to main() which worked on Linux but didn't seem workable on Windows, so I'm essentially recommending the same solution as someone else did previously, but with the additional explanation of why it is actually correct even if the results are not pretty.
As Minok mentioned, there is no such functionality specified ini C standard or C++ standard. This is considered to be purely OS-specific feature and it is specified in POSIX standard, for example.
Thorsten79 has given good suggestion, it is Boost.Filesystem library. However, it may be inconvenient in case you don't want to have any link-time dependencies in binary form for your program.
A good alternative I would recommend is collection of 100% headers-only STLSoft C++ Libraries Matthew Wilson (author of must-read books about C++). There is portable facade PlatformSTL gives access to system-specific API: WinSTL for Windows and UnixSTL on Unix, so it is portable solution. All the system-specific elements are specified with use of traits and policies, so it is extensible framework. There is filesystem library provided, of course.
The linux bash command
which progname will report a path to program.
Even if one could issue the which command from within your program and direct the output to a tmp file and the program
subsequently reads that tmp file, it will not tell you if that program is the one executing. It only tells you where a program having that name is located.
What is required is to obtain your process id number, and to parse out the path to the name
In my program I want to know if the program was
executed from the user's bin directory or from another in the path
or from /usr/bin. /usr/bin would contain the supported version.
My feeling is that in Linux there is the one solution that is portable.
Use realpath() in stdlib.h like this:
char *working_dir_path = realpath(".", NULL);
The following worked well for me on macOS 10.15.7
brew install boost
main.cpp
#include <iostream>
#include <boost/filesystem.hpp>
int main(int argc, char* argv[]){
boost::filesystem::path p{argv[0]};
p = absolute(p).parent_path();
std::cout << p << std::endl;
return 0;
}
Compiling
g++ -Wall -std=c++11 -l boost_filesystem main.cpp

Qt auto software version?

Does Qt maintain any sort of versioning information about your program like .NET does? Like the build number? Or does it provide an easy way to access the SVN revision?
No.
But if you're using qmake then you can set compiler flags in the build system based on the results of arbitrary commands, which might be usable to do what you want.
For example, if you were using git, you could do something like this in your .pro file:
REVISION = $$system(git rev-parse HEAD)
DEFINES += APP_REVISION=$$REVISION
That would give you an APP_REVISION macro when compiling your program, which you could use like this:
// stringize macro
#define _STR(X) #X
#define STR(X) _STR(X)
QTextStream(cout) << "MyApp revision " STR(APP_REVISION) << endl;

Resources