Wt a.exe file won't run - c++

I am trying to start developing in WT, but it's not working out. I am using Windows 8, downloaded Wt 3.3.1, and had downloaded the codeblocks-12.11mingw-setup_user.exe which has the GCC compiler and GDB debugger. But I am not using code blocks, because the compiler didn't like the cmake preproccessor directives in WtConfig.h. So I tried to compile manually (I am a newb at using this type of technique, so I had to look it up).
I have my project as:
└───HelloWorldWt
└───source
├───bin
│ ├───Debug
│ │ └───CMakeFiles
│ │ └───CMakeFiles
│ └───Release
├───build
└───source
| └───CMakeFiles
| └───wt_project.wt.dir
| |___CMakeLists.txt
| |
| |___main.cpp
|____CMakeLists.txt
The main.cpp has (this is the HelloWorld example from http://www.webtoolkit.eu/wt/examples/):
/*
* Copyright (C) 2008 Emweb bvba, Heverlee, Belgium.
*
* See the LICENSE file for terms of use.
*/
#include <Wt/WApplication>
#include <Wt/WBreak>
#include <Wt/WContainerWidget>
#include <Wt/WLineEdit>
#include <Wt/WPushButton>
#include <Wt/WText>
// c++0x only, for std::bind
// #include <functional>
using namespace Wt;
/*
* A simple hello world application class which demonstrates how to react
* to events, read input, and give feed-back.
*/
class HelloApplication : public WApplication
{
public:
HelloApplication(const WEnvironment& env);
private:
WLineEdit *nameEdit_;
WText *greeting_;
void greet();
};
/*
* The env argument contains information about the new session, and
* the initial request. It must be passed to the WApplication
* constructor so it is typically also an argument for your custom
* application constructor.
*/
HelloApplication::HelloApplication(const WEnvironment& env)
: WApplication(env)
{
setTitle("Hello world"); // application title
root()->addWidget(new WText("Your name, please ? ")); // show some text
nameEdit_ = new WLineEdit(root()); // allow text input
nameEdit_->setFocus(); // give focus
WPushButton *button
= new WPushButton("Greet me.", root()); // create a button
button->setMargin(5, Left); // add 5 pixels margin
root()->addWidget(new WBreak()); // insert a line break
greeting_ = new WText(root()); // empty text
/*
* Connect signals with slots
*
* - simple Wt-way
*/
button->clicked().connect(this, &HelloApplication::greet);
/*
* - using an arbitrary function object (binding values with boost::bind())
*/
nameEdit_->enterPressed().connect
(boost::bind(&HelloApplication::greet, this));
/*
* - using a c++0x lambda:
*/
// b->clicked().connect(std::bind([=]() {
// greeting_->setText("Hello there, " + nameEdit_->text());
// }));
}
void HelloApplication::greet()
{
/*
* Update the text, using text input into the nameEdit_ field.
*/
greeting_->setText("Hello there, " + nameEdit_->text());
}
WApplication *createApplication(const WEnvironment& env)
{
/*
* You could read information from the environment to decide whether
* the user has permission to start a new application
*/
return new HelloApplication(env);
}
int main(int argc, char **argv)
{
/*
* Your main method may set up some shared resources, but should then
* start the server application (FastCGI or httpd) that starts listening
* for requests, and handles all of the application life cycles.
*
* The last argument to WRun specifies the function that will instantiate
* new application objects. That function is executed when a new user surfs
* to the Wt application, and after the library has negotiated browser
* support. The function should return a newly instantiated application
* object.
*/
int retval = WRun(argc, argv, &createApplication);
char* ch = new ch();
cin() >> ch;
return retval;
}
The HelloWorldWt/CMakeLists.txt has:
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(WT_HELLO_WORLD)
SET (WT_CONNECTOR "wtfcgi" CACHE STRING "Connector used (wthttp or wtfcgi)")
ADD_SUBDIRECTORY(source)
The HelloWorldWt/source/CMakeLists.txt has
SET(WT_PROJECT_SOURCE
main.cpp
)
SET(WT_PROJECT_TARGET wt_project.wt)
ADD_EXECUTABLE(${WT_PROJECT_TARGET} ${WT_PROJECT_SOURCE})
TARGET_LINK_LIBRARIES(${WT_PROJECT_TARGET} ${WT_CONNECTOR} wt)
INCLUDE_DIRECTORIES("C:/Users/Me/My Code Libraries/wt-3.3.1/src")
I then ran
cmake .. -G "MinGW Makefiles" from the MyCode directory
That created a few files,
this created cmake_install.cmake, among other files.
I then ran: cmake .. -G "MinGW Makefiles" from HelloWorldWt/source
then I ran: cmake -P cmake_install.cmake
I then had:
My Code\HelloWorldWt\source\build\CMakeFiles\2.8.12\CompilerIdCXX\a.exe file, and I clicked that program to run it, and a console window just opened then closed.
what am I missing here?, I am trying to get a Wt application running, but can't seem to do it yet
(Maybe I should note that when I use the command:
cmake -P cmake_install.cmake
the cmd console, replies with
-- Install configuration: ""
and then goes back to the prompt. - If that helps).

My Code\HelloWorldWt\source\build\CMakeFiles\2.8.12\CompilerIdCXX\a.exe
Is not the file you want to run. It is an internal CMake test cmake creates during configuration to verify that the selected compiler even compiles and detect the target architecture.
You executable will be called
My Code\HelloWorldWt\source\build\wt_project.wt.exe
when you actually compile it.
To compile it, you either call make, or other appropriate build command depending on the selected generator, or you can ask cmake to call it for you with the command:
cmake --build .
The code you pasted contains syntax error—
cin() >> ch;
should be
std::cin >> ch;
(and ch should be a char, not char *)—which confirms you didn't yet try to compile it.
I should add that brief look at the WT documentation suggests the resulting executable should also need a bunch of options before it does anything interesting too.

We are using g++ since its a c++ interface (opposed to gcc), and scons as the build model. This works well and was pretty simple to deploy. I would suggest trying the next Ubuntu 14.04 release as it will contain a stable Wt version in its packages.

Related

Installation without Root Access in Linux

I have to compile Locally Aware NMS (lanms) in my remote server LINUX based with an user account without root access.
In lanms there is a script named adapter.cpp , I have to convert it to .pyd so that it works with python. I have given the code described here.
#include "pybind11/pybind11.h"
#include "pybind11/numpy.h"
#include "pybind11/stl.h"
#include "pybind11/stl_bind.h"
#include "lanms.h"
namespace py = pybind11;
namespace lanms_adaptor {
std::vector<std::vector<float>> polys2floats(const std::vector<lanms::Polygon> &polys) {
std::vector<std::vector<float>> ret;
for (size_t i = 0; i < polys.size(); i ++) {
auto &p = polys[i];
auto &poly = p.poly;
ret.emplace_back(std::vector<float>{
float(poly[0].X), float(poly[0].Y),
float(poly[1].X), float(poly[1].Y),
float(poly[2].X), float(poly[2].Y),
float(poly[3].X), float(poly[3].Y),
float(p.score),
});
}
return ret;
}
/**
*
* \param quad_n9 an n-by-9 numpy array, where first 8 numbers denote the
* quadrangle, and the last one is the score
* \param iou_threshold two quadrangles with iou score above this threshold
* will be merged
*
* \return an n-by-9 numpy array, the merged quadrangles
*/
std::vector<std::vector<float>> merge_quadrangle_n9(
py::array_t<float, py::array::c_style | py::array::forcecast> quad_n9,
float iou_threshold) {
auto pbuf = quad_n9.request();
if (pbuf.ndim != 2 || pbuf.shape[1] != 9)
throw std::runtime_error("quadrangles must have a shape of (n, 9)");
auto n = pbuf.shape[0];
auto ptr = static_cast<float *>(pbuf.ptr);
return polys2floats(lanms::merge_quadrangle_n9(ptr, n, iou_threshold));
}
}
PYBIND11_PLUGIN(adaptor) {
py::module m("adaptor", "NMS");
m.def("merge_quadrangle_n9", &lanms_adaptor::merge_quadrangle_n9,
"merge quadrangels");
return m.ptr();
}
To convert it I have used the following command.
cl adaptor.cpp ./include/clipper/clipper.cpp /I ./include /I "C:\ProgramData\Anaconda3\include" /LD /Fe:adaptor.pyd /link/LIBPATH:"C:\ProgramData\Anaconda3\libs"
It shows an error:
Command 'cl' not found, but can be installed with:
apt install cl-launch
Please ask your administrator.
Furthermore, I don't have the root access. Is there any other way to install "cl" without administrator privileges?
The other way to compile lanms is need to install the g++ compiler in order to compile the adaptar.cpp file.
sudo apt-get install build-essential
It is also asking for the administrator privileges.
I'm afraid, that it is almost impossible to compile your code on a machine that doesn't have a compiler installed.
The best option, that I can come up with, would be to set up a virtual machine, that runs the same version of the same linux distribution as the server. In that virtual machine, you have root access and can install a compiler. After compiling the code you just copy the program/library to the server. It is however not guaranteed, that the program compiled in the virtual machine will run without problems on the real server.

Attaching debugger give me the credentials, removing it and the credentials are empty

I have a problem with the AWS sdk on a Qt app.
I'm getting the STS tokens from Cognito after a click on a QML button.
The function is working perfectly fine and is printing me the token... as long as the debugger is attached [F5]. If I start the project without debugger (green arrow without bug on it) the returned object is empty.
Without the debugger attached I have the following in the aws logs that I don't have otherwise:
[INFO] 2020-09-18 12:33:02.569 CognitoCachingCredentialsProvider [140678610167936] A parent identity was from cognito which is different from the anonymous identity. Swapping that out now.
[INFO] 2020-09-18 12:33:02.569 CognitoCachingCredentialsProvider [140678610167936] Credentials will expire next at 0
Other logs around looks the same, I even have the STS token shown a couples of lines above this one on both cases:
[DEBUG] 2020-09-18 12:33:02.569 CURL [140678610167936] (DataIn) {"Credentials":{"AccessKeyId":"###","Expiration":1.600435982E9,"SecretKey":"###","SessionToken":"##########"},"IdentityId":"<MY_IDENTITY_ID>"}
I have even edited the SDK and added the following logs which resulted in this (with the debugger attached the first line is also getting <MY_IDENTITY_ID> shown).
AWS_LOGSTREAM_INFO("TOTO", "parentIdentityId" << parentIdentityId);
AWS_LOGSTREAM_INFO("TOTO", "m_identityRepository->GetIdentityId() " << m_identityRepository->GetIdentityId()) ;
[INFO] 2020-09-18 12:33:02.569 TOTO [140678610167936] parentIdentityId
[INFO] 2020-09-18 12:33:02.569 TOTO [140678610167936] m_identityRepository->GetIdentityId() <MY_IDENTITY_ID>
Added here https://github.com/aws/aws-sdk-cpp/blob/6d6dcdbfa377393306bf79585f61baea524ac124/aws-cpp-sdk-identity-management/source/auth/CognitoCachingCredentialsProvider.cpp#L52
No commenting the line 56 does not fix my problem.
Attached is my minimal project to reproduce the behavior if you want (You will need to have an AWS setup and an openID provider).
I tried on pure C++ and I get everything even without debugger.
The problem arises when instantiating the QtCoreApplication.
On the base app I tried setting a QTimer::singleShot(100, /*...*/) and I still got the problem.
You can install the aws SDK from here https://github.com/aws/aws-sdk-cpp and if you don't want to install the whole SDK, the project only need a little part of the sdk so add -DBUILD_ONLY="identity-management" to cmake to only build the needed part.
Qt 5.12.5
aws-sdk-cpp on tag: 1.8.42 (Had the same problem from previous patch version and the latest change very often)
Question
What magic attaching the debugger do to allow an application that instanciated a QCoreApplication getting tokens from the aws sdk ?
I am saying it again here: I do not have a DEBUG and a RELEASE build, I just use the arrow vs arrow with a bug on it in qtcreator. As far as I know the environment is the same, just qtcreator attach or not the debugger.
Indeed in release I have the same problem (STS shown when the debugger is attached, empty when not).
Minimal working example
main.cpp (The commented code should do the same as credentials = cognitoAuth.GetAWSCredentials();, and so I have the same behaviour.)
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <aws/cognito-identity/model/GetCredentialsForIdentityRequest.h>
#include <aws/cognito-identity/model/GetIdRequest.h>
#include <aws/core/Aws.h>
#include <aws/identity-management/auth/CognitoCachingCredentialsProvider.h>
#include <aws/identity-management/auth/PersistentCognitoIdentityProvider.h>
Aws::String m_region = Aws::Region::<PICK_YOUR_REGION>;
Aws::String m_providerUrl = "<PROVIDER_URL>";
Aws::String m_accountId = "<ACCOUNT_ID>";
Aws::String m_identityPoolId = "<IDENTITY_POOL_ID>";
Aws::Auth::AWSCredentials getSTS(const std::string idToken) {
const char *persistentFile = "/tmp/aws.identities";
QFile::remove(persistentFile);
Aws::Auth::AWSCredentials credentials;
// Aws::CognitoIdentity::Model::Credentials credentials;
std::shared_ptr<Aws::CognitoIdentity::CognitoIdentityClient> cognitoClient;
Aws::SDKOptions options;
options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Trace;
Aws::InitAPI(options);
{
Aws::Client::ClientConfiguration config;
config.region = m_region;
cognitoClient =
std::make_shared<Aws::CognitoIdentity::CognitoIdentityClient>(config);
std::shared_ptr<Aws::Auth::PersistentCognitoIdentityProvider_JsonFileImpl>
identityProvider = std::make_shared<
Aws::Auth::PersistentCognitoIdentityProvider_JsonFileImpl>(
m_identityPoolId, m_accountId, persistentFile);
Aws::Map<Aws::String, Aws::Auth::LoginAccessTokens> logins;
Aws::Auth::LoginAccessTokens loginAccessTokens;
loginAccessTokens.accessToken = idToken;
logins[m_providerUrl] = loginAccessTokens;
identityProvider->PersistLogins(logins);
// QThread::sleep(5);
Aws::Auth::CognitoCachingAuthenticatedCredentialsProvider cognitoAuth{
identityProvider, cognitoClient};
///////////////////////////////////////////////////////////////////////////
// Aws::CognitoIdentity::Model::GetIdRequest idRequest;
// idRequest.SetIdentityPoolId(m_identityPoolId.c_str());
// idRequest.AddLogins(m_providerUrl, idToken.c_str());
////idRequest.SetIdentityPoolId((region + ":" + identityPoolId).c_str());
//
// auto idResult = cognitoClient->GetId(idRequest);
// if(!idResult.IsSuccess())
//{
// qCWarning(mqttAwsWebsocket) << "(GetId): " <<
// idResult.GetError().GetExceptionName().c_str() << ":"
// <<
// idResult.GetError().GetMessage().c_str();
// // throw
//}
//
// QThread::sleep(5);
//
// Aws::CognitoIdentity::Model::GetCredentialsForIdentityRequest
// credForIdRequest;
// credForIdRequest.SetIdentityId(idResult.GetResult().GetIdentityId());
// credForIdRequest.AddLogins(m_providerUrl, idToken.c_str());
//
// auto credForIdResult =
// cognitoClient->GetCredentialsForIdentity(credForIdRequest);
// if(!idResult.IsSuccess())
//{
// qCWarning(mqttAwsWebsocket) << "(GetCredentialsForIdentity): "
// <<
// credForIdResult.GetError().GetExceptionName().c_str()
// << ":"
// <<
// credForIdResult.GetError().GetMessage().c_str();
// // throw
//}
//
// qDebug() << "COGNITO STS TOKEN RESULTS";
// qDebug() << "cognitoClient->GetId: " << idResult.IsSuccess();
// qDebug() << "cognitoClient->GetCredentialsForIdentity: " <<
// credForIdResult.IsSuccess(); credentials =
// credForIdResult.GetResult().GetCredentials();
///////////////////////////////////////////////////////////////////////////
// QThread::sleep(5);
credentials = cognitoAuth.GetAWSCredentials();
qDebug() << credentials.IsEmpty() << tries;
qDebug() << credentials.GetAWSAccessKeyId().c_str();
qDebug() << credentials.GetAWSSecretKey().c_str();
qDebug() << credentials.GetSessionToken().c_str();
qDebug() << credentials.IsExpired()
<< credentials.GetExpiration()
.ToLocalTimeString(Aws::Utils::DateFormat::RFC822)
.c_str();
}
Aws::ShutdownAPI(options);
return credentials;
}
int main(int argc, char **argv) {
// Comment just this line and the problem is fixed.
QCoreApplication app(argc, argv);
getSTS("<PAST_OPEN_ID_TOKEN_GOTTEN_FROM_REAL_APP>");
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(aws-sts LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt5 COMPONENTS Core)
set(BUILD_SHARED_LIBS ON)
find_package(AWSSDK REQUIRED COMPONENTS identity-management)
add_executable(aws-sts main.cpp)
target_link_libraries(aws-sts PRIVATE
Qt5::Core
${AWSSDK_LINK_LIBRARIES}
)
Update
I simplified the minimal working example since in fact just adding (or commenting ot) QCoreApplication app(argc, argv); is sufficient to reproduce the behavior. I mean just the object creation, no need for it to be a QGuiApplication or start the event loop with app.exec().
It turns out that the aws sdk is using cJSON which, when parsing numbers, may or may not get the local environment for decoding decimal point. But in both cases it will call double strtod(const char *nptr, char **endptr); to translate string to double, in the man page we can read (emphasis mine)
A decimal number consists of a nonempty sequence of decimal digits possibly containing a radix character (decimal point, locale-dependent, usually '.'), optionally followed by a decimal exponent. [...]
Apparently cJSON need this compilation variable to compile on Android.
AWS copied the lib here but did not copied the compilation variable ENABLE_LOCALES which should be enabled by default as stated in the issue linked above.
I am on Ubuntu 18.04, environment in English but dates/number in French (decimal point is ',' here in France).
I am creating an issue on the AWS SDK repo to set the compilation variable ENABLE_LOCALES and on cJSON to discuss and avoid further error like this one.
A potential fix could also be to force the application to use English locales but that is not always possible.

Bash autocomplete an option without running the application

I have found this code as a bash autocomplete. But, it looks strange to me. What if I do not like to run the code at all. If I would like to type ./a.out then space (without entering) and then by pressing tab, I would like to see only two options apple and cherry and if I type a and press tab, then it autocomplete the option apple and similarly for c. Let's say only one of the two options are acceptable:
./a.out apple
./a.out cherry
where apple and cherry are options and not the name of the files in the directory. In the first case, I would like the program types that your option is apple and in the second case your option is cherry. In any other case, the program should print an error that the option is not valid.
All examples that I find on the internet such as what follows look like that you should run the program first, then it reacts. The while loop inside the main function collides with the normal functionality of the program. Have I misunderstood the readline library? Is the above-described application possible to implement by editing the following code?
// sudo apt-get install libreadline-dev
// g++ -std=c++11 main.cpp -lreadline
#include <iostream>
#include "readline/readline.h"
#include "readline/history.h"
using namespace std;
int main(int argc, char** argv)
{
const char *line;
while ((line = readline("? ")) != nullptr) {
cout << "[" << line << "]" << endl;
if (*line) add_history(line);
free(line);
}
// if(argc!=2)
// {
// cout<<"<exe> one_parameter"<<endl;
// return 1;
// }
// string option=argv[1];
// if(option=="apple" || option=="cherry")
// cout<<"Your option is "<<option<<endl;
// else
// {
// cout<<"Error: invalid option "<<option<<endl;
// return 1;
// }
return 0;
}
// partial answer - why you may want to invoke the app while doing the autocompletion
One way of implementing the autocomplete for an application is to have the application binary configure it (by having a flag that prints the instructions for autocomplete configuration or by just parsing the --help output of the application).
Schemataically:
complete -F $(./a.out --generate-autocomplete-config) ./a.out
This is why you might see the binary actually invoked as a part of autocomplete implementation.
This has nothing to do with your executable. You need to put this in a file and source (source autocomplete_file or . autocomplete_file) it in the bash.
_a_complete_()
{
local word=${COMP_WORDS[COMP_CWORD]}
local files='apple cherry'
COMPREPLY=( $( compgen -W "${files}" -- ${word} ) )
}
complete -F _a_complete_ ./a.out
Here a nice documentation can be found.

how can I synchronize a gtk::label with the creation or suppression of a file in a directory?

I have a program who lists all files in the working directory (I use glib for doing this), then I screen this list in a GtkWindow trough a Gtk::Label. I screen the window by using run(),
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "Zombie-Shadowchaser SixSixSix");
app->run(*pMainWindow);
I know how to change the label with set_label() I can synchronize the list of files in the directory with the list screened trough the click of a button. So if I delete or create a file, it will remove or add to the label the file. But how can I make my program to synchronize every second without clicking ?
here a full example, is also good to study if you are looking to understand how to use g_signal_connect()
#include <gtkmm.h>
Gtk::Label *plabel; // because I"m lazzy...
/**
** everytime a file is created in the current directory, toCallbackFunction()
** will be called. The paramaters are the same of signal see signal here :
** http://www.freedesktop.org/software/gstreamer-sdk/data/docs/latest/gio/GFileMonitor.html#GFileMonitor-changed
**/
void
toCallbackFunction(GFileMonitor *monitor
,GFile *file
,GFile *other_file
,GFileMonitorEvent event_type
,gpointer user_data
)
{
plabel->set_label( g_file_get_path(file) );
}
int
main(int argc
,char *argv[]
)
{
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "org.gtkmm.examples.base");
Gtk::Window window;
Gtk::Label label;
window.set_default_size(800, 200);
label.set_label("test");
window.add(label);
label.show();
plabel = &label;
/*
* g_file_monitor() requires a file, not a path. So we use g_file_new_for_path()
* to convert the directory (this is for demonstration)
*/
GFile *file = g_file_new_for_path(".");
GFileMonitor *monitor;
/*
* http://www.freedesktop.org/software/gstreamer-sdk/data/docs/latest/gio/GFile.html#g-file-monitor
*/
monitor = g_file_monitor_directory(file, G_FILE_MONITOR_NONE, nullptr, nullptr);
/*
* the next line, is how to connect the monitor to a callback function when
* the signal changed has been triggered.
*/
g_signal_connect(monitor, "changed", G_CALLBACK (toCallbackFunction), nullptr);
return app->run(window);
}
compile on linux :
g++ main.cc -o simple `pkg-config gtkmm-3.0 --cflags --libs` -std=c++11
for MS Windows users, I'm not racist, but I don't know how to compile on windows. Any comment would be apreciate, I made this piece of code by my own. Thx to report any error.
How to use it :
when you start the program, go with your console in the same directory and create a new file, for example,
$ echo "stack" > overflow
you should get something like :
Thx to nemequ

Using PCRE on ILE

I am trying to use the pcre library (from AIX) on IBM iseries.
It should be possible using PASE.
I installed the pcre library with the rpm provided by yips.
I tried to use it in c ile source, but i couldn't achieve it.
Exemples : yips, ibm, ibm redbook
I can't find the way to do it.
Here is what i have done so far.
#include <stdio.h>
#include <qp2shell2.h>
#include <qp2user.h>
#define JOB_CCSID 0
int main(int argc, char *argv[])
{
int rc;
QP2_ptr64_t id;
void *getpid_pase;
const QP2_arg_type_t signature[] = { QP2_ARG_END };
QP2_word_t result;
/*
* Call QP2SHELL2 to run the OS/400 PASE program
* /usr/lib/start32, which starts OS/400 PASE in
* 32-bit mode (and leaves it active on return)
*/
QP2SHELL2("/usr/lib/start32");
/*
* Qp2dlopen opens the global name space (rather than
* loading a new shared executable) when the first
* argument is a null pointer. Qp2dlsym locates the
* function descriptor for the OS/400 PASE getpid
* subroutine (exported by shared library libc.a)
*/
id = Qp2dlopen("/usr/lib/libpcre.a", QP2_RTLD_NOW, JOB_CCSID);
getpid_pase = Qp2dlsym(id, "pcrecpp::RE", JOB_CCSID, NULL);
//id = Qp2dlopen(NULL, QP2_RTLD_NOW, JOB_CCSID);
//getpid_pase = Qp2dlsym(id, "getpid", JOB_CCSID, NULL);
/*
* Call Qp2CallPase to run the OS/400 PASE getpid
* function, and print the result. Use Qp2errnop
* to find and print the OS/400 PASE errno if the
* function result was -1
*/
rc = Qp2CallPase(getpid_pase,
NULL, // no argument list
signature,
QP2_RESULT_WORD,
&result);
printf("OS/400 PASE getpid() = %i\n", result);
if (result == -1)
printf("OS/400 errno = %i\n", *Qp2errnop());
/*
* Close the Qp2dlopen instance, and then call
* Qp2EndPase to end OS/400 PASE in this job
*/
Qp2dlclose(id);
Qp2EndPase();
return 0;
}
Today I tried the same and I could compile pcre to ILE using CRTCMOD.
In the zip-file of pcre you can find a file named NON_AUTOTOOLS_BUILD (if I remember the name correctly) with with all information needed to compile it.
In fact you only need to:
edit config.h to match your environment (available functions like memmove, features like pthreads, EBCDIC support and NewLine=37 (x'25') )
compile dftables.c using CRTBNDC DEFINE(HAVE_CONFIG_H) ...
CALL DFTABLES to generate the character tables for EBCDIC (this step was a bit tricky, because it couldn't open the IFS-File for output. so I put the output in a source member and used CPYTOSTMF to get it in the IFS)
compile the all the .c files unsing CRTCMOD DEFINE(HAVE_CONFIG_H) ...
create a *SRVPGM from the modules
write the Prototypes for RPG
It works like a charm, except for a little problem with CCSIDs. I generated the chartables for CCSID 1141, but for some reason PCRE expects input to be CCSID 37.
Also note that, if you write the prototypes in RPG, pcre_free is special. This function is not implemented in PCRE (you could write your own and plug it in if you want) and defaults to free. Your prototype should look like
Dpcre_free PR EXTPROC('free')
D * value
*white spaces not accurate
Hope that helps