How would one approach adding support for https://github.com/tianocore/edk2-libc, say I want to include stdio and use printf in my edk2 application? I followed StdLib/Readme.txt, and am able to successfully build examples in the AppPkg, however, when I try to add StdLib to my project I get errors like these:
LibString.lib(Searching.obj) : error LNK2005: strspn already defined in LibString.lib(Searching.obj)
LibCtype.lib(CClass.obj) : error LNK2005: isspace already defined in LibCtype.lib(CClass.obj)
(...)
LibC.lib(Main.obj) : error LNK2001: unresolved external symbol main
I do have the boilerplate (!include StdLib/StdLib.inc) added to my dsc file and in inf, I have StdLib.dec added to Packages and LibC and LibStdio added to LibraryClasses. I am using VS2017 toolchain for compilation and am using edk2-stable202108 release.
I was able to achieve this using below configuration for Hello Application of AppPkg.
Hello.inf
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = Hello
FILE_GUID = a912f198-7f0e-4803-b908-b757b806ec83
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 0.1
ENTRY_POINT = ShellCEntryLib
#
# VALID_ARCHITECTURES = IA32 X64
#
[Sources]
Hello.c
[Packages]
MdePkg/MdePkg.dec
ShellPkg/ShellPkg.dec
StdLib/StdLib.dec
[LibraryClasses]
UefiLib
ShellCEntryLib
BaseLib
BaseMemoryLib
MemoryAllocationLib
LibStdLib
LibStdio
LibString
DevConsole
Hello.c
#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/ShellCEntryLib.h>
#include <stdio.h>
int
main (
IN int Argc,
IN char **Argv
)
{
printf("Hello, world!\n");
return 0;
}
What I have understood is that LibC has ShellAppMain() defined in it which internally calls extern main(). So You need to provide definition of main() in your source just like I did in Hello.c
I'm trying to set a connection to postgre database, but having linker errors.
.pro file:
QT -= gui
CONFIG += c++11 console
CONFIG -= app_bundle
CONFIG += sql
DEFINES += QT_DEPRECATED_WARNINGS
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
unix|win32: LIBS += -L$$PWD/../../PostgreSQL/12/lib/ -llibpq
INCLUDEPATH += $$PWD/../../PostgreSQL/12/include
DEPENDPATH += $$PWD/../../PostgreSQL/12/include
win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../PostgreSQL/12/lib/libpq.lib
else:unix|win32-g++: PRE_TARGETDEPS += $$PWD/../../PostgreSQL/12/lib/liblibpq.a
.cpp file:
#include <QCoreApplication>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSql>
#include <QtSql/QSqlDriver>
#include <QTextStream>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QSqlDatabase mDB=QSqlDatabase::addDatabase("QPSQL");
return a.exec();
}
It's just that. I'm not even trying to connect yet.
Errors are:
main.obj:-1: error: LNK2019: unresolved external symbol "__declspec(dllimport) public: __cdecl QSqlDatabase::~QSqlDatabase(void)" (__imp_??1QSqlDatabase##QEAA#XZ) referenced in function main
main.obj:-1: error: LNK2019: unresolved external symbol "__declspec(dllimport) public: static class QSqlDatabase __cdecl QSqlDatabase::addDatabase(class QString const &,class QString const &)" (__imp_?addDatabase#QSqlDatabase##SA?AV1#AEBVQString##0#Z) referenced in function main
main.obj:-1: error: LNK2001: unresolved external symbol "__declspec(dllimport) public: static char const * const QSqlDatabase::defaultConnection" (__imp_?defaultConnection#QSqlDatabase##2PEBDEB)
Postge is 64bit for Windows, compiler chosen for this application is also 64 MSVC2019 64bit. Please help.
Problem was in .pro file. It should be:
QT += sql
and not:
CONFIG += sql
I am developing a Qt application that, among other things, converts an Excel spreadsheet in a text delimited with tab file. This is done by running a Windows Powershell script.
My problem is that the finished() signal from the QProcess is never emitted, although the conversion is done successfully. And yes, I receive stateChanged() signal.
Powershell script (ps_excel.ps1)
(adapted from this question)
param ([string]$ent = $null, [string]$sal = $null)
$xlCSV = -4158 #value for tab delimited file
$Excel = New-Object -Com Excel.Application
$Excel.visible = $False
$Excel.displayalerts=$False
$b = $Excel.Workbooks.Open($ent)
$b.SaveAs($sal,$xlCSV)
$Excel.quit()
exit 0 #tested without exit, with exit and with exit 0
Qt app header
(For testing, the minimal case is a QDialog without other widgets.)
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QProcess>
#include <QDebug>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
QProcess *proces;
private:
Ui::Dialog *ui;
private slots:
void procFinish(int estat);
void procState(QProcess::ProcessState estat);
};
#endif // DIALOG_H
Qt app C++
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
QString program = "C:/Windows/System32/WindowsPowerShell/v1.0/powershell.exe";
QStringList params;
params << "-File" << "C:/Garsineu/ps_excel.ps1" << "-ent" << "C:/Garsineu/PROVAGALATEA.xls" << "-sal" << "C:/Garsineu/PROVAGALATEA.tab";
proces = new QProcess();
connect(proces, SIGNAL(finished(int)), this, SLOT(procFinish(int)));
connect(proces, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(procState(QProcess::ProcessState)));
proces->start(program, params);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::procFinish(int estat)
{
qDebug() << "Finished";
}
void Dialog::procState(QProcess::ProcessState estat)
{
qDebug() << estat;
}
Although the conversion is successful and the states 1 (Started) and 2 (Running) are shown, the message "Finished" is never displayed.
I also tried to do it synchronously, by waitForFinished () method, which is always timed out.
Environment
Windows 7 Professional 64 bit
Powershell v1.0 x86
Qt 5.4.0 with minGW491_32
I appreciate your help. Thank you.
I found the solution. Apparently Powershell does not run in the same way from the console or when is called from another program (noninteractive). If I add at end of ps_excel.ps1 script:
Get-Process Powershell | Stop-Process
instead of
exit 0
I Stop really Powershell and get finished signal, with QProcess::ExitStatus = 0.
I have a chrome packaged app that also includes a PNaCl/NaCl C++ module, as well as some data files which the NaCl module needs to read in. However, I am not able to get it to read in the files.
I set it up according to all the documentation and official examples that I could find, as well as the answer to: How to include a data file in a chrome app for a native client module to read
The nacl_io demo that comes with the SDK is able to do this, but it is in C, not C++.
I came up with a simple example, which I'll post below. When you press the button on the page, the NaCl module should load the first character of test.txt and show it. As of now, it always just responds with "-100" (the error value I put in), meaning that it could not open the file, rather than with the first character of the file.
Can anyone suggest some changes that would allow it to work correctly and load the file?
In order to run it, on the Mac at least, I use this command, with all the files in the ./file-test dir:
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --load-and-launch-app=./file-test
Note that if you try to use this, you will most likely need to change the NACL_SDK_ROOT path in the makefile.
file_test.cc
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"
#include "nacl_io/nacl_io.h"
#include "sys/mount.h"
class FileTestInstance : public pp::Instance {
public:
explicit FileTestInstance(PP_Instance instance) : pp::Instance(instance)
{
// initialize nacl file system
nacl_io_init_ppapi(instance, pp::Module::Get()->get_browser_interface());
// mount the http root at /http
mount("", "/http", "httpfs", 0, "");
}
virtual ~FileTestInstance() {}
// Receive message from javascript
virtual void HandleMessage(const pp::Var& var_message) {
// Open and load from the file
int c;
FILE *file;
file = fopen("/http/test.txt", "r");
if (file) {
c = getc(file);
fclose(file);
} else {
c = -100;
}
// Send message to JavaScript
pp::Var var_reply(c);
PostMessage(var_reply);
}
};
class FileTestModule : public pp::Module {
public:
FileTestModule() : pp::Module() {}
virtual ~FileTestModule() {}
virtual pp::Instance* CreateInstance(PP_Instance instance) {
return new FileTestInstance(instance);
}
};
namespace pp {
Module* CreateModule() {
return new FileTestModule();
}
} // namespace pp
index.html
<!DOCTYPE html>
<html>
<head>
<title>File Test</title>
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<h1>File Test</h1>
<input type="button" id="test" name="test" value="Test" />
<p><b>Output:</b><p>
<div id="output">
</div>
<p>
<div id="listener">
<embed id="file_test" width=0 height=0 src="file_test.nmf" type="application/x-pnacl" />
</div>
</p>
</body>
</html>
script.js
// outgoing messages
function postMessage(message) {
var nacl_module = document.getElementById('file_test')
nacl_module.postMessage(message);
}
// incoming messages
function handleMessage(message_event) {
var outputDiv = document.getElementById('output');
outputDiv.textContent = message_event.data;
}
// button action
function buttonClicked() {
postMessage("file");
}
// set up
function init() {
// add listener to nacl module
var listener = document.getElementById('listener');
listener.addEventListener('message', handleMessage, true);
// add action to button
document.getElementById("test").onclick = buttonClicked;
}
window.onload = init;
main.js
/**
* Listens for the app launching then creates the window
*/
chrome.app.runtime.onLaunched.addListener(function() {
// Center window on screen.
var screenWidth = screen.availWidth;
var screenHeight = screen.availHeight;
var width = 600;
var height = 600;
chrome.app.window.create('index.html', {
id: "File-TestID",
bounds: {
width: width,
height: height,
left: Math.round((screenWidth-width)/2),
top: Math.round((screenHeight-height)/2)
}
});
});
file_test.nmf
{
"program": {
"portable": {
"pnacl-translate": {
"url": "file_test.pexe"
}
}
}
}
Makefile
#
# Get pepper directory for toolchain and includes.
#
# If NACL_SDK_ROOT is not set, then assume where it can be found.
#
THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST)))
NACL_SDK_ROOT ?= $(abspath $(dir $(THIS_MAKEFILE))../../nacl_sdk/pepper_33)
# Project Build flags
WARNINGS := -Wno-long-long -Wall -Wswitch-enum -pedantic -Werror
CXXFLAGS := -pthread -std=gnu++98 $(WARNINGS)
#
# Compute tool paths
#
GETOS := python $(NACL_SDK_ROOT)/tools/getos.py
OSHELPERS = python $(NACL_SDK_ROOT)/tools/oshelpers.py
OSNAME := $(shell $(GETOS))
RM := $(OSHELPERS) rm
PNACL_TC_PATH := $(abspath $(NACL_SDK_ROOT)/toolchain/$(OSNAME)_pnacl)
PNACL_CXX := $(PNACL_TC_PATH)/bin/pnacl-clang++
PNACL_FINALIZE := $(PNACL_TC_PATH)/bin/pnacl-finalize
CXXFLAGS := -I$(NACL_SDK_ROOT)/include -I$(NACL_SDK_ROOT)/include/pnacl
LDFLAGS := -L$(NACL_SDK_ROOT)/lib/pnacl/Release -lppapi_cpp -lppapi -lnacl_io
#
# Disable DOS PATH warning when using Cygwin based tools Windows
#
CYGWIN ?= nodosfilewarning
export CYGWIN
# Declare the ALL target first, to make the 'all' target the default build
all: file_test.pexe
clean:
$(RM) file_test.pexe file_test.bc
file_test.bc: file_test.cc
$(PNACL_CXX) -o $# $< -O2 $(CXXFLAGS) $(LDFLAGS)
file_test.pexe: file_test.bc
$(PNACL_FINALIZE) -o $# $<
test.txt
AAAA
From Sam Clegg on the native-client-discuss list:
"I think the main problem you have is that you are trying to use nacl_io on the main thread. nacl_io, like the blocking PPAPI interfaces on which it is mostly based, will only work on background threads where blocking calls are allowed. See:
https://developer.chrome.com/native-client/devguide/coding/nacl_io."
"Try running your code on a separate thread. One easy way to do this is to use the ppapi_simple library."
Using this advice, and also looking at the examples using_ppapi_simple, flock, and earth, that are included with the SDK, I was able to make a working version:
file_test.cc
#include <stdio.h>
#include "sys/mount.h"
#include <ppapi/cpp/var.h>
#include "ppapi_simple/ps_main.h"
#include "ppapi_simple/ps_event.h"
#include "ppapi_simple/ps_interface.h"
int file_test_main(int argc, char* argv[]) {
PSEventSetFilter(PSE_ALL);
// mount the http root at /http
mount("", "/http", "httpfs", 0, "");
while (true) {
PSEvent* ps_event;
// Consume all available events
while ((ps_event = PSEventWaitAcquire()) != NULL) {
// handle messages from javascript
if (ps_event->type == PSE_INSTANCE_HANDLEMESSAGE) {
// Convert Pepper Simple message to PPAPI C++ vars
pp::Var var_message(ps_event->as_var);
// process the message if it is a string
if (var_message.is_string()) {
// get the string message
std::string message = var_message.AsString();
// handle message
if (message == "file") {
// Open and load from the file
int c;
FILE *file;
file = fopen("/http/test.txt", "r");
if (file) {
c = getc(file);
fclose(file);
} else {
c = -100;
}
// Send response back to JavaScript
pp::Var var_reply(c);
PSInterfaceMessaging()->PostMessage(PSGetInstanceId(), var_reply.pp_var());
}
}
}
PSEventRelease(ps_event);
}
}
return 0;
}
/*
* Register the function to call once the Instance Object is initialized.
* see: pappi_simple/ps_main.h
*/
PPAPI_SIMPLE_REGISTER_MAIN(file_test_main)
In addition, it is necessary to add -lppapi_simple to LDFLAGS in Makefile.
It would also be possible to do this handling the threads oneself, rather than using ppapi_simple, which can be seen in nacl_io_demo which is included with the SDK.
The Qt page does not list pre-compiled Qt 5 packages for Solaris. Searching around, it does not seem to be included in the popular package repository OpenCSW, either. Some google hits suggest that building Qt 5 under Solaris involves some work under Solaris 10.
Thus my question: How to build Qt 5.2 under Solaris 10?
Basically it is:
cd qt-everywhere-opensource-src-5.2.0
./configure -prefix $MY_PREFIX -opensource -confirm-license -nomake tests \
-R /opt/csw/lib/64 -R /opt/csw/X11/lib/64 -qt-xcb -platform solaris-g++-64 \
-verbose
gmake -j16
gmake -j16 install
plus some adjustments because Qt 5 does not seem to be used on
Solaris much, yet.
Adjustments
Obtain the source
wget http://download.qt-project.org/official_releases/qt/5.2/5.2.0/single/qt-everywhere-opensource-src-5.2.0.tar.gz
md5sum qt-everywhere-opensource-src-5.2.0.tar.gz
228b6384dfd7272de00fd8b2c144fecd qt-everywhere-opensource-src-5.2.0.tar.gz
If the system does not habe md5sum you can use openssl md5 filename instead.
Install dependencies
I recommend to use OpenCSW because we need some dependencies to build Qt. The most important ones are:
CSWlibxcbdevel
CSWlibicu-dev # soft-dependency
CSWgcc4g++
CSWgmake
I suggest to use GCC to compile Qt. I am not aware of any advantages using the C++ compiler from Solaris Studio. On the contrary, the level of C++/STL support of this compiler may be not sufficient for a lot of use cases.
Setup environment
Make sure that you environment is clean. That means that /opt/csw/bin comes first and no LD_LIBRAYR_PATH* variables are set.
To simplify things it is probably a good idea that some directories are removed from PATH. For example such that no cc, CC commands from a Solaris Studio installation are accidentally picked up (e.g. during the compile of a bundled 3rd party component.
Adjust the specs
The software under /usr/sfw is just too outdated. /opt/csw from OpenCSW is a better replacement. Then the X-Open version is not sufficient for some used system functions.
--- a/qtbase/mkspecs/solaris-g++-64/qmake.conf
+++ b/qtbase/mkspecs/solaris-g++-64/qmake.conf
## -35,7 +35,7 ## QMAKE_LEX = flex
QMAKE_LEXFLAGS =
QMAKE_YACC = yacc
QMAKE_YACCFLAGS = -d
-QMAKE_CFLAGS = -m64 -D_XOPEN_SOURCE=500 -D__EXTENSIONS__
+QMAKE_CFLAGS = -m64 -D_XOPEN_SOURCE=600 -D__EXTENSIONS__
QMAKE_CFLAGS_DEPS = -M
QMAKE_CFLAGS_WARN_ON = -Wall -W
QMAKE_CFLAGS_WARN_OFF = -w
## -58,8 +58,8 ## QMAKE_CXXFLAGS_STATIC_LIB = $$QMAKE_CFLAGS_STATIC_LIB
QMAKE_CXXFLAGS_YACC = $$QMAKE_CFLAGS_YACC
QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD
-QMAKE_INCDIR = /usr/sfw/include
-QMAKE_LIBDIR = /usr/sfw/lib/64
+QMAKE_INCDIR = /opt/csw/include /opt/csw/X11/include
+QMAKE_LIBDIR = /opt/csw/lib/64 /opt/csw/X11/lib/64
QMAKE_INCDIR_X11 = /usr/openwin/include
QMAKE_LIBDIR_X11 = /usr/openwin/lib/64
QMAKE_INCDIR_OPENGL = /usr/openwin/include
Fix the shell
Solaris comes with a /bin/sh that violates POSIX to an extend such
that Qt's configure scripts and even shell-code in qmake-generated
code fails.
POSIX does not specify that /bin/sh has to be conforming it just specifies that the system must have a conforming shell available 'somewhere'. On Solaris it is e.g. under /usr/xpg4/bin/sh. The portable way to get a conforming shell is to search for it in the directories returned by getconf CS_PATH ...
Anyways, my choice for Solaris is to just use /usr/bin/bash:
Anyways, my choice for Solaris is to just use /usr/bin/bash:
--- a/configure
+++ b/configure
## -1,4 +1,4 ##
-#! /bin/sh
+#!/usr/bin/bash
#############################################################################
##
## Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
--- a/qtbase/configure
+++ b/qtbase/configure
## -1,4 +1,4 ##
-#!/bin/sh
+#!/usr/bin/bash
#############################################################################
##
## Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
## -6892,7 +6892,7 ## fi'`
echo "$CONFIG_STATUS" | grep '\-confirm\-license' >/dev/null 2>&1 || CONFIG_STATUS="$CONFIG_STATUS -confirm-license"
[ -f "$outpath/config.status" ] && rm -f "$outpath/config.status"
- echo "#!/bin/sh" > "$outpath/config.status"
+ echo "#!/usr/bin/bash" > "$outpath/config.status"
[ -n "$PKG_CONFIG_SYSROOT_DIR" ] && \
echo "export PKG_CONFIG_SYSROOT_DIR=$PKG_CONFIG_SYSROOT_DIR" >> "$outpath/config.status"
[ -n "$PKG_CONFIG_LIBDIR" ] && \
--- a/qtbase/qmake/generators/makefile.cpp
+++ b/qtbase/qmake/generators/makefile.cpp
## -2306,6 +2306,10 ## MakefileGenerator::writeHeader(QTextStream &t)
if (ofile.lastIndexOf(Option::dir_sep) != -1)
ofile.remove(0, ofile.lastIndexOf(Option::dir_sep) +1);
t << "MAKEFILE = " << ofile << endl << endl;
+
+ t << "# custom mod because Solaris /bin/sh is such a standard-violating choice\n"
+ << "# - gs, 2013-12-23" << endl;
+ t << "SHELL = /usr/bin/bash" << endl << endl;
}
QList<MakefileGenerator::SubTarget*>
Fix the ICU test
Solaris 10 comes with an outdated libicu - which is missing features Qt 5 needs. Thus, we simply extend the icu-test. Then either no ICU-support is build or proper one in case we install a recent libicu e.g. via OpenCSW.
--- a/qtbase/config.tests/unix/icu/icu.cpp
+++ b/qtbase/config.tests/unix/icu/icu.cpp
## -43,6 +43,16 ##
#include <unicode/ucol.h>
#include <unicode/ustring.h>
+// for testing if ucal_clone is there (i.e. if we have libicu >= 4.0)
+#include <unicode/ucal.h>
+
+static UCalendar *ucp(UCalendar *i)
+{
+ UErrorCode status = U_ZERO_ERROR;
+ UCalendar *r = ucal_clone(i, &status);
+ return r;
+}
+
int main(int, char **)
{
UErrorCode status = U_ZERO_ERROR;
## -50,5 +60,10 ## int main(int, char **)
if (U_FAILURE(status))
return 0;
ucol_close(collator);
+
+ UCalendar *cal = ucal_open(0, -1, "C", UCAL_GREGORIAN, &status);
+ UCalendar *x = ucp(cal);
+ ucal_close(x);
+
return 0;
}
Fix bundled pcre
Perhaps alternatively one can install a libpcre via OpenCSW.
--- a/qtbase/src/3rdparty/pcre/pcre_compile.c
+++ b/qtbase/src/3rdparty/pcre/pcre_compile.c
## -66,6 +66,8 ## COMPILE_PCREx macro will already be appropriately set. */
#endif
+#include <stdint.h>
+
/* Macro for setting individual bits in class bitmaps. */
#define SETBIT(a,b) a[(b)/8] |= (1 << ((b)&7))
Fix sha3
At least on Solaris 10/Sparc the functions fromBytesToWord and fromWordtoBytes are used by the code, thus:
--- a/qtbase/src/3rdparty/sha3/KeccakF-1600-opt64.c
+++ b/qtbase/src/3rdparty/sha3/KeccakF-1600-opt64.c
## -324,7 +324,7 ## static void KeccakPermutation(unsigned char *state)
KeccakPermutationOnWords((UINT64*)state);
}
-#if 0 // Unused in the Qt configuration
+#if 1 // Unused in the Qt configuration
static void fromBytesToWord(UINT64 *word, const UINT8 *bytes)
{
unsigned int i;
## -445,7 +445,7 ## static void KeccakAbsorb(unsigned char *state, const unsigned char *data, unsign
#endif
}
-#if 0 // Unused in the Qt configuration
+#if 1 // Unused in the Qt configuration
static void fromWordToBytes(UINT8 *bytes, const UINT64 word)
{
unsigned int i;
Include/type/usage fixes
The uname() function is activated via a CPP construct on Solaris
and is declared in that header:
--- a/qtbase/src/corelib/io/qfileselector.cpp
+++ b/qtbase/src/corelib/io/qfileselector.cpp
## -51,6 +51,8 ##
#include <QtCore/QLocale>
#include <QtCore/QDebug>
+#include <sys/utsname.h>
+
QT_BEGIN_NAMESPACE
//Environment variable to allow tooling full control of file selectors
Under Solaris parent is unused in that code-path and the code gets compiled with -Werror ...
--- a/qtbase/src/corelib/io/qfilesystemwatcher.cpp
+++ b/qtbase/src/corelib/io/qfilesystemwatcher.cpp
## -77,6 +77,7 ## QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject
#elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC)
return QKqueueFileSystemWatcherEngine::create(parent);
#else
+ (void)parent;
return 0;
#endif
}
Under Solaris uid_t has an 'unexpected' sign (-> Werror). Casting it to ssize_t should be a portable and safe choice:
--- a/qtbase/src/corelib/io/qstandardpaths_unix.cpp
+++ b/qtbase/src/corelib/io/qstandardpaths_unix.cpp
## -132,7 +132,7 ## QString QStandardPaths::writableLocation(StandardLocation type)
}
// "The directory MUST be owned by the user"
QFileInfo fileInfo(xdgRuntimeDir);
- if (fileInfo.ownerId() != myUid) {
+ if (fileInfo.ownerId() != ssize_t(myUid)) {
qWarning("QStandardPaths: wrong ownership on runtime directory %s, %d instead of %d", qPrintable(xdgRuntimeDir),
fileInfo.ownerId(), myUid);
return QString();
Similar issue with threading code (Werror because of sign-mismatch in pointer cast). Casting to size_t should be a portable safe choice:
--- a/qtbase/src/corelib/thread/qthread_unix.cpp
+++ b/qtbase/src/corelib/thread/qthread_unix.cpp
## -231,7 +231,7 ## QThreadData *QThreadData::current()
}
data->deref();
data->isAdopted = true;
- data->threadId = (Qt::HANDLE)pthread_self();
+ data->threadId = (Qt::HANDLE)((size_t)pthread_self());
if (!QCoreApplicationPrivate::theMainThread)
QCoreApplicationPrivate::theMainThread = data->thread;
}
## -314,7 +314,7 ## void *QThreadPrivate::start(void *arg)
thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
}
- data->threadId = (Qt::HANDLE)pthread_self();
+ data->threadId = (Qt::HANDLE)((size_t)pthread_self());
set_thread_data(data);
data->ref();
## -393,7 +393,7 ## void QThreadPrivate::finish(void *arg)
Qt::HANDLE QThread::currentThreadId() Q_DECL_NOTHROW
{
// requires a C cast here otherwise we run into trouble on AIX
- return (Qt::HANDLE)pthread_self();
+ return (Qt::HANDLE)((size_t)pthread_self());
}
#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
The struct in_addr has a struct as first attribute on Solaris, thus gives a warning with GCC when initializing with {0} - thus, yields an error during Qt-compile:
--- a/qtbase/src/network/socket/qnativesocketengine_unix.cpp
+++ b/qtbase/src/network/socket/qnativesocketengine_unix.cpp
## -63,6 +63,7 ##
#endif
#include <netinet/tcp.h>
+#include <string.h>
QT_BEGIN_NAMESPACE
## -737,7 +738,8 ## QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const
return QNetworkInterface::interfaceFromIndex(v);
}
- struct in_addr v = { 0 };
+ struct in_addr v;
+ memset(&v, 0, sizeof(struct in_addr));
QT_SOCKOPTLEN_T sizeofv = sizeof(v);
if (::getsockopt(socketDescriptor, IPPROTO_IP, IP_MULTICAST_IF, &v, &sizeofv) == -1)
return QNetworkInterface();
The header comment of X11/Xutil.h lists X11/Xutil.h as dependency, and indeed, without that include some declarations are missing under Solaris.
--- a/qtbase/src/plugins/platforms/xcb/qxcbmime.cpp
+++ b/qtbase/src/plugins/platforms/xcb/qxcbmime.cpp
## -46,6 +46,7 ##
#include <QtCore/QBuffer>
#include <qdebug.h>
+#include <X11/Xlib.h>
#include <X11/Xutil.h>
#undef XCB_ATOM_STRING
The X11/extensions/XIproto.h is not C++-safe under Solaris. That means it contains struct members names class. Fortunately, the header does not seem to be used in that code.
--- a/qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp
+++ b/qtbase/src/plugins/platforms/xcb/qxcbxsettings.cpp
## -43,7 +43,7 ##
#include <QtCore/QByteArray>
-#include <X11/extensions/XIproto.h>
+//#include <X11/extensions/XIproto.h>
QT_BEGIN_NAMESPACE
/* Implementation of http://standards.freedesktop.org/xsettings-spec/xsettings-0.5.html */
The pow() function has some overloads as specified in the C++ standard which introduce ambiguities under Solaris. Fixing the types like this should be portable and safe:
--- a/qtdeclarative/src/qml/jsruntime/qv4globalobject.cpp
+++ b/qtdeclarative/src/qml/jsruntime/qv4globalobject.cpp
## -534,7 +534,7 ## ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx)
}
if (overflow) {
- double result = (double) v_overflow * pow(R, overflow_digit_count);
+ double result = (double) v_overflow * pow(double(R), int(overflow_digit_count));
result += v;
return Encode(sign * result);
} else {
Under Solaris, alloca needs another header:
--- a/qtdeclarative/src/qml/jsruntime/qv4stringobject.cpp
+++ b/qtdeclarative/src/qml/jsruntime/qv4stringobject.cpp
## -73,6 +73,11 ##
# include <windows.h>
#endif
+
+#if OS(SOLARIS)
+#include <alloca.h>
+#endif
+
using namespace QV4;
DEFINE_MANAGED_VTABLE(StringObject);
Fix deep mkdir
Qt does a 'deep' mkdir() (e.g. something like mkdir -p for e.g. creating a directory hierarchy, e.g. ~/.config/company/product. The Qt 5.2 algorithm may abort too soon on Solaris if an existing directory is located inside a non-writable NFS mounted parent - because in that case Solaris returns EACCESS instead of EEXIST.
--- a/qtbase/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/qtbase/src/corelib/io/qfilesystemengine_unix.cpp
## -579,6 +579,11 ## bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool crea
// on the QNet mountpoint returns successfully and reports S_IFDIR.
|| errno == ENOENT
#endif
+#if defined(Q_OS_SOLARIS)
+ // On Solaris 10, mkdir returns EACCESS on a directory which exists
+ // inside an NFS mount ...
+ || errno == EACCES
+#endif
) {
QT_STATBUF st;
if (QT_STAT(chunk.constData(), &st) == 0 && (st.st_mode & S_IFMT) == S_IFDIR)
Temporary files
Solaris also does not have mkdtemp():
--- a/qtbase/src/corelib/io/qtemporarydir.cpp
+++ b/qtbase/src/corelib/io/qtemporarydir.cpp
## -52,7 +52,7 ##
#endif
#include <stdlib.h> // mkdtemp
-#if defined(Q_OS_QNX) || defined(Q_OS_WIN) || defined(Q_OS_ANDROID)
+#if defined(Q_OS_QNX) || defined(Q_OS_WIN) || defined(Q_OS_ANDROID) || defined(Q_OS_SOLARIS)
#include <private/qfilesystemengine_p.h>
#endif
## -96,7 +96,7 ## static QString defaultTemplateName()
static char *q_mkdtemp(char *templateName)
{
-#if defined(Q_OS_QNX ) || defined(Q_OS_WIN) || defined(Q_OS_ANDROID)
+#if defined(Q_OS_QNX ) || defined(Q_OS_WIN) || defined(Q_OS_ANDROID) || defined(Q_OS_SOLARIS)
static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
const size_t length = strlen(templateName);
Pthreads
Solaris does not have pthread_get_stacksize_np (the _np suffix stands for non-portable).
Solaris has another function for getting stack-address/size values. My attempt:
--- a/qtdeclarative/src/qml/jsruntime/qv4engine.cpp
+++ b/qtdeclarative/src/qml/jsruntime/qv4engine.cpp
## -73,6 +73,11 ##
#include "qv4isel_moth_p.h"
#if USE(PTHREADS)
+
+#if OS(SOLARIS)
+#include <thread.h>
+#endif
+
# include <pthread.h>
#endif
## -103,6 +108,11 ## quintptr getStackLimit()
} else
size = pthread_get_stacksize_np(thread_self);
stackLimit -= size;
+# elif OS(SOLARIS)
+ stack_t ss;
+ int r = thr_stksegment(&ss);
+ (void)r;
+ stackLimit = reinterpret_cast<quintptr>(ss.ss_sp);
# else
void* stackBottom = 0;
pthread_attr_t attr;
--- a/qtdeclarative/src/qml/jsruntime/qv4mm.cpp
+++ b/qtdeclarative/src/qml/jsruntime/qv4mm.cpp
## -67,6 +67,11 ##
#include <sys/storage.h> // __tls()
#endif
+#if OS(SOLARIS)
+#include <thread.h>
+#include <pthread.h>
+#endif
+
QT_BEGIN_NAMESPACE
using namespace QV4;
## -218,6 +223,11 ## MemoryManager::MemoryManager()
# if OS(DARWIN)
void *st = pthread_get_stackaddr_np(pthread_self());
m_d->stackTop = static_cast<quintptr *>(st);
+# elif OS(SOLARIS)
+ stack_t ss;
+ int r = thr_stksegment(&ss);
+ (void)r;
+ m_d->stackTop = static_cast<quintptr *>(ss.ss_sp) + ss.ss_size/sizeof(quintptr);
# else
void* stackBottom = 0;
pthread_attr_t attr;
I recommend a careful review of that code because my Qt-code does not use that Qt-module, thus, I did not test it much.
XKB extension
Qt 5 seems to heavily rely on the XKB extension. It seems that you can't build Qt 5 without XKB support. It comes bundled with xkbcommon.
First, make sure that it finds the right XKB database. Otherwise keyboard input does not work at all in your Qt programs!
Solaris does not have the default value /usr/share/X11/xkb. It has instead:
/usr/X11/lib/X11/xkb
/usr/openwin/lib/X11/xkb
But I havn't had luck with those - xkbcommon simply could not find any components with those.
I ended up with copying /usr/share/X11/xkb from a cygwin distribution to a custom path and configuring that as XKB database.
Whatever XKB you choose you have to configure it:
--- a/qtbase/src/3rdparty/xkbcommon.pri
+++ b/qtbase/src/3rdparty/xkbcommon.pri
## -1,7 +1,12 ##
QMAKE_CFLAGS += -std=gnu99 -w
INCLUDEPATH += $$PWD/xkbcommon $$PWD/xkbcommon/src $$PWD/xkbcommon/src/xkbcomp
+solaris-g++-64 {
+DEFINES += DFLT_XKB_CONFIG_ROOT='\\"/MY/XKB/CHOICE\\"'
+} else {
DEFINES += DFLT_XKB_CONFIG_ROOT='\\"/usr/share/X11/xkb\\"'
+}
### RMLVO names can be overwritten with environmental variables (See libxkbcommon documentation)
DEFINES += DEFAULT_XKB_RULES='\\"evdev\\"'
For testing it also make sense to check for NULL values in error message parameters:
--- a/qtbase/src/3rdparty/xkbcommon/src/xkbcomp/xkbcomp.c
+++ b/qtbase/src/3rdparty/xkbcommon/src/xkbcomp/xkbcomp.c
## -68,8 +68,11 ## text_v1_keymap_new_from_names(struct xkb_keymap *keymap,
log_err(keymap->ctx,
"Couldn't look up rules '%s', model '%s', layout '%s', "
"variant '%s', options '%s'\n",
- rmlvo->rules, rmlvo->model, rmlvo->layout, rmlvo->variant,
- rmlvo->options);
+ rmlvo->rules, rmlvo->model,
+ rmlvo->layout ? rmlvo->layout : "(NULL)",
+ rmlvo->variant ? rmlvo->variant : "(NULL)",
+ rmlvo->options ? rmlvo->options : "(NULL)"
+ );
return false;
}
There is also the possibility that your XServer does not even support the XKB extension. Again, I don't know if Qt 5 can be configured with disabled-XKB-support under X.
You can check your X-server like this:
xprop -root | grep xkb
Or call a random xkb-program, e.g.:
xkbvleds
Such call should not result in an error like:
Fatal Error: Server doesn't support a compatible XKB
In case your XServer does not have XKB - Qt programs are likely to segfault. Qt does not seem to really check for XKB support. It does not seem to have a fallback mechanism when XKB is not usable.
Examples
Some examples fail because of module quick not being found:
--- a/qtconnectivity/examples/bluetooth/scanner/scanner.pro
+++ b/qtconnectivity/examples/bluetooth/scanner/scanner.pro
## -1,4 +1,4 ##
-QT = core bluetooth quick
+QT = core bluetooth # quick
SOURCES += qmlscanner.cpp
TARGET = qml_scanner
diff --git a/qtconnectivity/examples/nfc/poster/poster.pro b/qtconnectivity/examples/nfc/poster/poster.pro
index d108b2a..d0d0659 100644
--- a/qtconnectivity/examples/nfc/poster/poster.pro
+++ b/qtconnectivity/examples/nfc/poster/poster.pro
## -1,4 +1,4 ##
-QT += qml quick network nfc widgets
+QT += qml network nfc widgets # quick
SOURCES += \
qmlposter.cpp
They are also built without.
make install
A gmake install surprisingly triggers the compilation of several modules not yet compiled. Thus it make sense to execute it in parallel:
$ gmake -j16 install
(assuming that your system has a sufficient number of cores)
QtHelp
The bundled QtHelp module is not build/installed with the main compile/install steps.
To fix that:
cd qttools
PATH=$MY_PREFIX/bin:$PATH qmake
gmake
gmake install
Open issues
when using a remote Cygwin-X connection some colors are weird - e.g. the standard widget-gray is some light-light-blue - any ideas where to start to look for that?
QtSVG is successfully built but displaying a small SVG (e.g. inside a QLabel) hangs the dialog - a truss -u : shows function calls inside libm/QtWidget - perhaps the system is just way too slow and/or some code-path is not optimized on Solaris/in combination with a X-forwarding over ssh
a Qt-Program prints on startup: Qt Warning: Could not find a location of the system's Compose files. Consider setting the QTCOMPOSE environment variable. - no idea what feature this is about
Conclusion
With those adjustments 'normal' Qt programs (without QtSvg) compile
and run fine under Solaris 10.