Running an C++ exetuable with embedded python - python-3.8

I am on Windows 10, having installed WinPython 64 3.8.5 and Mingw w64.
I want to call python code from C++ and started using the following example code:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
int main(int argc, char *argv[])
{
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
if (program == NULL) {
fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
exit(1);
}
Py_SetProgramName(program); /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print('Today is', ctime(time()))\n");
if (Py_FinalizeEx() < 0) {
exit(120);
}
PyMem_RawFree(program);
return 0;
}
Compilation runs through smoothly (g++ myfile.cpp -Ipath/to/Python.h -Lpath/to/python38.lib -lpython38)
However, when running the exe in cmd (after running C:\Users\liebschs\Programs\WinPython64-3.8.5\WPy64-3850\scripts\env.batch in that cmd), I obtain the following error:
Python path configuration:
PYTHONHOME = (not set)
PYTHONPATH = (not set)
program name = 'embed.exe'
isolated = 0
environment = 1
user site = 1
import site = 1
sys._base_executable = 'C:\\Users\\liebschs\\MyFiles\\playground\\VSprojects\\EmbedPython\\embed.exe'
sys.base_prefix = 'C:\\Users\\liebschs\\Programs\\WinPython64-3.8.5\\WPy64-3850\\python-3.8.5.amd64'
sys.base_exec_prefix = 'C:\\Users\\liebschs\\Programs\\WinPython64-3.8.5\\WPy64-3850\\python-3.8.5.amd64'
sys.executable = 'C:\\Users\\liebschs\\MyFiles\\playground\\VSprojects\\EmbedPython\\embed.exe'
sys.prefix = 'C:\\Users\\liebschs\\Programs\\WinPython64-3.8.5\\WPy64-3850\\python-3.8.5.amd64'
sys.exec_prefix = 'C:\\Users\\liebschs\\Programs\\WinPython64-3.8.5\\WPy64-3850\\python-3.8.5.amd64'
sys.path = [
'C:\\Users\\liebschs\\Programs\\WinPython64-3.8.5\\WPy64-3850\\python-3.8.5.amd64\\python38.zip',
'.\\DLLs',
'.\\lib',
'C:\\Users\\liebschs\\MyFiles\\playground\\VSprojects\\EmbedPython',
]
Fatal Python error: init_fs_encoding: failed to get the Python codec of the filesystem encoding
Python runtime state: core initialized
ModuleNotFoundError: No module named 'encodings'
Current thread 0x000021c8 (most recent call first):
<no Python frame>
Any help is appreciated!
Btw:
Running python scripts directly (i.e. doing "python helloworld.py" in cmd) or using pip does not cause an error and runs as expected.
switching to a virtual environment, does not change anything

Contrary to what I read elsewhere, the problem is resolved when I set PYTHONPATH and PYTHONHOME to the python.exe, in my case C:\Users\liebschs\Programs\WinPython64-3.8.5\WPy64-3850\python-3.8.5.amd64

Related

Unable to open file after FUSE mount

I'm trying out FUSE for the first time by following the official GitHub Repo's example.
I have done the following:
created a mount directory called mount_dir that contains file hello.txt.
update /etc/fuse.conf with user_allow_other as mentioned in various forums and posts
Added bunch of printf() statements in hello_ll.c at all function entry points.
Executed ./hello_ll -o allow_other -f /home/hemalkumar/mount_dir
Executed ./test_stat. It calculate the number of pages in the file. Just some business logic, nothing fancy!
test_stat.c
#define PAGE_SIZE 4096
int main() {
char* filename = "/home/hemalkumar/mount_dir/hello.txt";
int fd = open(filename, O_RDONLY);
if (fd == -1) {
printf("INVALID file:%s\n", filename);
close(fd);
return -1;
}
struct stat sb;
if (fstat(fd, &sb) == -1) {
close(fd);
return -1;
}
int pages = sb.st_size/PAGE_SIZE + (sb.st_size % PAGE_SIZE != 0);
printf("pages:%d\n", pages);
return 0;
}
Issue:
When I execute test_stat without mounting FUSE, it works fine. However, running it after step#4 shows an error INVALID file:/home/hemalkumar/mount_dir/hello.txt.
I have updated /etc/fuse.conf file to allow other user, and passing flags during startup of hello_ll. Don't know what permission issues it is having.
Any pointers will be appreciated!
Thanks!

JNI header missing in Objective-C

I have a file.c in my project which has #include <jni.h> header file. What is the process to include this header file in project or macOS?
Let's say you have following code
#include "jni.h"
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
JNIEnv *env;
JavaVM *jvm;
JavaVMInitArgs vm_args;
JavaVMOption options[3];
options[0].optionString = "-Djava.class.path=_HERE_GOES_LOCATION_OF_JNICOOKBOK_/jnicookbook/recipeNo051/target";
vm_args.options = options;
vm_args.ignoreUnrecognized = 0;
vm_args.version = JNI_VERSION_1_8;
vm_args.nOptions = 1;
int status = JNI_CreateJavaVM (&jvm, (void **) &env, &vm_args);
if (status < 0 || !env) {
printf ("Error - JVM creation failed\n");
return 1;
}
jclass cls_Main = (*env)->FindClass (env, "recipeNo051/Main");
jmethodID method_displayMessage = (*env)->GetStaticMethodID (env, cls_Main, "displayMessage", "()V");
(*env)->CallStaticVoidMethod(env, cls_Main, method_displayMessage);
(*jvm)->DestroyJavaVM( jvm );
}
return 0;
}
in order to run it you will need
location of libjvm.dylib
location of headers
location of compiled Java classes that are called from main.m
Let's start with libs and headers. You have to make sure that following paths are searched for includes (note that I am using jdk-11.0.4):
/Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home/include
/Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home/include/darwin/
You have to make sure that following path is added to Library Search Path and to Runpath Search Paths
/Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home/lib/server
You should have settings like that:
Make sure you are linking your code with libjvm.dylib. Add it inside Build Phases
where you can specify it's location by choosing Add Other...
Run your code, but! Make sure to ignore SIGSEGV before calling method JNI_CreateJavaVM. You can ignore it inside lldb console
(lldb) process handle --pass true --stop false SIGSEGV
After you continue, you can see your JVM instance calling classes from the recipeNo051.
Source code of class: recipeNo051/Main can be found here: https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo051
Update
step by step instructions: http://www.owsiak.org/running-jni-based-code-inside-xcode/
video tutorial: https://youtu.be/WEA-3uI7Y18

./speaks: error while loading shared libraries: libespeak-ng.so.1: cannot open shared object file: No such file or directory

I have downloaded the last version of espeak-ng from github, and did ./autogen.sh ./configure make make install.
so I wrote a test program as you can see below:
#include <string.h>
#include <vector>
#include </usr/local/include/espeak-ng/speak_lib.h>
int samplerate; // determined by espeak, will be in Hertz (Hz)
const int buflength = 200; // passed to espeak, in milliseconds (ms)
std::vector<short> sounddata;
int SynthCallback(short *wav, int numsamples, espeak_EVENT *events) {
if (wav == NULL)
return 1; // NULL means done.
/* process your samples here, let's just gather them */
sounddata.insert(sounddata.end(), wav, wav + numsamples);
return 0; // 0 continues synthesis, 1 aborts
}
int main(int argc, char* argv[] ) {
char text[] = {"my name is espeak"};
samplerate = espeak_Initialize(AUDIO_OUTPUT_RETRIEVAL, buflength, NULL, 0);
espeak_SetSynthCallback(&SynthCallback);
espeak_SetVoiceByName("en");
unsigned int flags=espeakCHARS_AUTO | espeakENDPAUSE;
size_t size = strlen(text);
espeak_Synth(text, size + 1, 0, POS_CHARACTER, 0, flags, NULL, NULL);
espeak_Synchronize();
/* in theory sounddata holds your samples now... */
return 0;
}
And compiled it by this command without any errors:
g++ -W -o speaks espeak.cpp -lespeak-ng
But when I try to run the executable by ./speaks , I get this error message:
./speaks: error while loading shared libraries: libespeak-ng.so.1: cannot open shared object file: No such file or directory
What's the problem?
I know libespeak-ng.so.1 is here: /usr/local/lib/libespeak-ng.so.1
I solved the problem by adding these two lines to my `/etc/environment' file:
LD_LIBRARY_PATH=/usr/local/lib
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
On Ubuntu 18.04 this is caused by setting the wrong path for the library.
You can fix it by:
sudo ln -s /usr/local/lib/libespeak-ng.so.1 /usr/lib/libespeak-ng.so.1

How to get dylib version information which are in a directory

I wanted to get the dylib version. I've a dylib path for which I wanted to get the version number.
I've tried "otool -L" command and it's giving me the proper output but as per the requirements I can't use it, since I've 100 of dylib in a directory for which I wanted to get the version information and I can't run "otool" command for each dylib through NSTask and NSPipe.
I've also found the NSVersionOfLinkTimeLibrary() function to get the dylib version, but as per the documentation NSVersionOfLinkTimeLibrary returns the version number for linked libraries and not for other dylib.
Any help on this would be helpful.
Thanks.
Omkar
I've solved it by writing my own dylib parser. Below is the code snippet
- (int64_t)getDylibVersion :(NSString *)dylibPth
{
const char* strFilePath = [dylibPth UTF8String];
FILE* fileHandle = fopen(strFilePath, "rb");
struct mach_header mh;
if(fileHandle)
{
size_t bytesRead = fread(&mh, 1, sizeof(mh), fileHandle);
if(bytesRead == sizeof(mh))
{
if((mh.magic == MH_MAGIC_64 || mh.magic == MH_MAGIC) && mh.filetype == MH_DYLIB)
{
for(int j = 0; j < mh.ncmds; j++)
{
union
{
struct load_command lc;
struct dylib_command dc;
} load_command;
if (sizeof(load_command.lc) != fread(&load_command.lc, 1, sizeof(load_command.lc), fileHandle))
goto fail;
switch (load_command.lc.cmd)
{
case LC_SEGMENT:
break;
case LC_UUID:
break;
case LC_DYLD_INFO_ONLY:
break;
case LC_SYMTAB:
break;
case LC_LOAD_DYLIB:
break;
case LC_ID_DYLIB:
{
if (sizeof(load_command) - sizeof(load_command.lc) != fread(&load_command.lc + 1, 1, sizeof(load_command) - sizeof(load_command.lc), dylib_handle))
goto fail;
fclose(fileHandle);
return(load_command.dc.dylib.current_version);
}
default:
break;
}
if (0 != fseek(fileHandle, load_command.lc.cmdsize - sizeof(load_command.lc), SEEK_CUR))
goto fail;
}
}
}
}
fail:
fclose(fileHandle);
return (-1);
}
Note that Mach-O dylib version numbers are encoded as 32-bit unsigned integers, with the major version in the high 16 bits, the minor version in bits 8 through 15, and the patch level in the low 8 bits:
uint32_t version = …;
uint32_t major = version >> 16;
uint32_t minor = (version >> 8) & 0xff;
uint32_t revision = version & 0xff;
Note also that the above code will only work for "thin" binaries. "Fat," multi-architecture binaries start with a fat header, which you'll need to negotiate first to find the slice for your desired architecture. Moreover, the above only works with architectures of the running architecture's endianness.
The way I see it, you have 2 options.
Load each dylib into your process and lookup the Mach-O headers on each, looking for the version numbers. The documentation should be complete and thorough enough to get you started.
Open each dylib as a normal file, and read and parse the Mach-O headers yourself. This avoid having to load each dylib into the process, but it does mean you need to then either parse the Mach-O binary format yourself, or find a library that can do it for you (I don't know of any off the top of my head).

What is causing this command line error?

I am trying to programatically call the "top" command. The following is the code used:
char buffer [128];
char* threadsPointer;
char* procPointer;
NSString* numberOfThreadsString;
NSString* numberOfProcString;
FILE* output = popen("/usr/bin/top", "r");
while (fgets(buffer, sizeof(buffer), output) != NULL)
{
if ((procPointer = strstr(buffer, "Processes:")) != NULL)
{
procPointer += strlen("Proceses: ");
strcpy(buffer, procPointer);
numberOfProcString = [NSString stringWithUTF8String: buffer];
}
if ((threadsPointer = strstr(buffer, "sleeping,")) != NULL)
{
threadsPointer += strlen("sleeping, ");
strcpy(buffer, threadsPointer);
numberOfThreadsString = [NSString stringWithUTF8String: buffer];
}
}
NSLog(#"Proc: %#\nThreads: %#\n\n\n", numberOfProcString, numberOfThreadsString);
Instead of giving valid output, I keep getting the error: "Error opening terminal: unknown". I commended out the whole piece of code to identify the problem, and realized that its the line: FILE* output = popen ("/usr/bin/top", "r"); that is causing the error.
Does anyone have an idea of what I am doing wrong? Note I am on Mountain Lion OS X building an app for OSX not iOS.
top on MacOSX requires that its standard output or standard error be connected to a valid terminal to run. When you invoke it without a terminal (or a $TERM environment variable set to a valid terminal name, like "vt100"), it gives you that error: Error opening terminal: unknown.
You really shouldn't be using top for this, since it's an interactive program that requires a terminal. You should just be using ps.
you can try "top -l 1".
"-l 1" mean 1 sample, I think it should run top in non-interactive mode, print the result and exit.
On linux the command is "top -n 1" ("-n 1" mean run only 1 iteration, which should be equivalent to "top -l 1" on mac osx).
If you want specific information or all the details you should use "/proc" filesystem.
You can readdir() and fopen() all the files in /proc which contains currently running processes and get a lot of information, like for example what files are open by some process, or what ports is the process listening on.
'top' command opens a terminal and waits for user input. You won't be able to use it in a an automated script