I wanted to try a program distributed in source for *nux on Windows. It's simple program with couple of C source files and headers
I have Mingw/Msys and first I tried to compile it there, by running make, but unfortunatelly I get obscure error (.text+0x175): undefined reference to 'strsep' which maight indicate a problem with autotools or similar, according Google search, but that's all about it I could get
As I mentioned that it is a simple program, I also tried to compile it with VS2008, until I figured it uses unix header file for parsing command line arguments, so nothing I can do there too
I launched my Ubuntu laptop and compiled the program in second, and tested it all fine, then I copy binary in my Windows Msys folder. No luck again as file can't be execeted (under Msys prompt of course) - it doesn't have execute flag and chmod on Msys has a "feature" that makes chmod +x unavailable
Update:
This is the error I get from msys prompt while trying to compile:
f77_diagram.c: In function 'handle_goto':
f77_diagram.c:57:4: warning: implicit declaration of function 'strsep' [-Wimplicit-function-declaration]
[...]
gcc -o f77_diagram block.o do_loop.o f77_diagram.o if.o label.o \
links.o parse_fortran.o
f77_diagram.o:f77_diagram.c:(.text+0x175): undefined reference to `strsep'
collect2: ld returned 1 exit status
That means that the function/variable strsep wasn't properly initialized. It most likely is a linking error. All it probably means is that you don't have a dependency installed. You'll need to post more information about the error.
By the way, you can't run linux binaries on windows.
Judging by your error, it looks like your compiler doesn't support the strsep function. To deal with this you will probably have to code your own, like this:
char *strsep(char **from, const char *delim) {
char *s, *dp, *ret;
if ((s = *from) == NULL)
return NULL;
ret = s;
while (*s != '\0') {
/* loop until the end of s, checking against each delimiting character,
* if we find a delimiter set **s to '\0' and return our previous token
* to the user. */
dp = (char *)delim;
while (*dp != '\0') {
if (*s == *dp) {
*s = '\0';
*from = s + 1;
return ret;
}
dp++;
}
s++;
}
/* end of string case */
*from = NULL;
return ret;
}
Here is the process that you will have to go through:
1- Find the file f77_diagram.c in the src directory.
2- Copy and paste the above code right after the #include statements.
3- Return to your command shell in the main make directory.
4- Re-run ./configure
5- Re-run make
If this doesn't work, there are a few other things you could try.
MSYS provides a Linux-like build environment for Windows. However, Linux binaries use the ELF or A.OUT formats, rather than the EXE format. Since there is nothing like WINE for Windows, Linux binaries have to be recompiled for Windows.
Related
Suppose source code file name is test.cpp. When it is compiled, it produce test.exe file. When I execute it, it should identify its file name that is test.exe and print it.
I'm able to get list of all the files and directories present in the current directory using following code:
DIR * directory;
struct dirent * direct;
direct = readdir(directory);
But, how can I identify the associated file name, in this case which is "test.exe"?
In your main function, argv[0] is the name of the executable from the command line
#include <stdio.h>
int main(int argc, char ** argv)
{
printf("%s", argv[0]);
return 0;
}
Live Demo
This prints the command name, which is the directory relative to the current working directory, plus the executable name (if available, which is not guaranteed)
To get the current working directory, use getcwd() standard library C function.
Extracting the file name from the command path in argv[0] is platform specific : unix use slashes '/', windows allows mixed uses of slash / and backslash \, and any other platform could use any other path separator. Extracting the file name from a path requires a cross-platform library, such as Qt or Boost. On POSIX environments, basename could be used.
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("%s\n", argv[0]);
return 0;
}
Note that your program can be launched as:
/home/user/./app
In this case you can get the name by using strrchr:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *appname;
appname = strrchr(argv[0], '/'); /* '\\' on Windows */
printf("%s\n", appname ? ++appname : argv[0]);
return 0;
}
You know the name of the executable when you're building it; the
simplest solution is to embed it in the program, using a -D or /D
option to define a macro on the command line.
Other than that, the generic answer is that it isn't possible:
According to the standard
argv[0] should contain the name which was used to invoke the
program (whatever that means). Which is nice, but 1) it isn't even
implementable under Unix, and 2) under most systems, there are all sorts
of aliasing which means that the name used to invoke the program bears
no relationship to the name of the executable.
Under Windows
There's a system function GetModuleFileName which can be used to
obtain the path of the executable. Once you've got the path, the last
element of the path is the name of your executable.
Under Unix
It's fundamentally impossible. When starting a new process, Unix
takes separate arguments for the path to the executable and for what
ends up in argv[0], so they can potentially have no relationship to
one another. It all depends on who starts your process. bash will
put the full path to the executable in the environment variable "_",
so you can use getenv to get it. But that only works if your program
was started by bash. On most Unices, you can also find it in the
/proc filesystem, if you know your way around there; but the
organization of this varies from one Unix to the next. Note too that
because of hard links, you're executable may not have just one
name.
The real question is why you want to do this. What is the problem you
are trying to solve?
On Linux specifically:
you might use proc(5) and the /proc/self/exe symlink, so use readlink(2) on that. Once you did that, you could use basename(3) or realpath(3) on the obtained symlink.
However, be aware that a program might not always have a file path. It could have several file paths (for example /bin/rbash is a symlink to /bin/bash, and the shell process behave differently when invoked as rbash or as bash). Sometimes a given file (actually an inode, see inode(7)) has several hardlinks to it. In weird cases there is none.
And it could happen that a program is execve(2)-ed and then removed with unlink(2) (perhaps from another process scheduled to run before yours) etc..
(BTW, your question is OS specific; readdir(3) is POSIX and there are some operating systems not even having directories, and readdir is not mentioned by the C11 standard; check by reading n1570)
I experimented with the following (pathological) ./selfremove program (in my /home/basile/tmp/ directory) which removes its own binary:
// file selfremove.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int
main (int argc, char **argv)
{
char selfpath[128];
memset (selfpath, 0, sizeof (selfpath));
if (readlink ("/proc/self/exe", selfpath, sizeof (selfpath) - 1) < 0)
{
perror ("first readlink");
exit (EXIT_FAILURE);
};
printf ("initial /proc/self/exe -> %s\n", selfpath);
if (unlink (argv[0]))
{
fprintf (stderr, "unlink %s: %m\n", argv[0]);
exit (EXIT_FAILURE);
};
printf ("%s unlinked\n", argv[0]);
if (readlink ("/proc/self/exe", selfpath, sizeof (selfpath) - 1) < 0)
{
perror ("second readlink");
exit (EXIT_FAILURE);
};
printf ("final /proc/self/exe -> %s\n", selfpath);
return 0;
}
It works, and the kernel is constructing a * (deleted) symlink (since a perverse coder might rename an executable as selfremove (deleted), so that kernel added suffix is only an indication ....):
% ./selfremove
initial /proc/self/exe -> /home/basile/tmp/selfremove
./selfremove unlinked
final /proc/self/exe -> /home/basile/tmp/selfremove (deleted)
So even with /proc/self/exe you cannot always trust the result.
If you assume that your program has been execve(2)-ed by some shell (or similar program doing execvp(3)) -and that is not always the case- then the PATH variable might have been used (and searched from your main's argv[0] if it has no /). You might use getenv(3) as getenv("PATH") to get it from your environment (see environ(7) for more). That $PATH is generally set and used, but they are pathological cases too.
So in general there is no way to reliably print its own executable (as my pathological selfremove.c demonstrates). In most cases you could find it (e.g. by readlink of /proc/self/exe, or by searching in $PATH using argv[0]).
In Linux systems, I think you can also use basename(char *path); from libgen.h,
try $ man basename:
Print NAME with any leading directory components removed. If specified, also remove a trailing SUFFIX.
I tried it as:
// filename.c
#include<stdio.h>
#include<stdlib.h>
#include<libgen.h>
int main(int argc, char* argv[]){
char* exe_name = basename(argv[0]);
printf(" Executable Name: %s", exe_name);
printf("\n");
return EXIT_SUCCESS;
}
Observations,compiled and tested it as:
taxspanner#:~$ ls filename.c
filename.c
taxspanner#:~$ gcc -std=gnu99 -Wall -pedantic filename.c -o filename
taxspanner#:~$ ls filename*
filename filename.c
taxspanner#:~$
Now run it in current directory:
taxspanner#:~$ ./filename
Executable Name: filename
Using absolute path:
taxspanner#:~$ pwd
/home/taxspanner
taxspanner#:~$ /home/taxspanner/filename
Executable Name: filename
Relative path:
taxspanner#:~$ cd study/divide-5/
taxspanner#:~/study/divide-5$ pwd
/home/taxspanner/study/divide-5
taxspanner#:~/study/divide-5$ ls ../../filename*
../../filename ../../filename.c
taxspanner#:~/study/divide-5$ ../../filename
Executable Name: filename
taxspanner#:~/study/divide-5$
one more try with executable name with suffix:
taxspanner#:~$ gcc -std=gnu99 -Wall -pedantic filename.c -o filename.out
taxspanner#:~$ ./filename.out
Executable Name: filename.out
taxspanner#:~$ cd study/divide-5/
taxspanner#:~/study/divide-5$ ../../filename.out
Executable Name: filename.out
Be careful when using it: Both dirname() and basename() may modify the contents of path, so it may be desirable to pass a copy when calling one of these functions.
Give it a try!!
I am trying to build wxHaskell for wxWidgets 3.0. I used the latest git version of wxHaskell from https://github.com/wxHaskell/wxHaskell.
I tried to follow install.txt in wxHaskell-master.zip, what I did so far is:
cd wxdirect
cabal install
cd ../wxc
cabal install
wxc won't compile because its Setup.hs requires wxWidgets 2.9. I replaced
let wxRequiredVersion = "2.9"
with
let wxRequiredVersion = "3.0"
and then did:
cabal install --extra-lib-dirs=/usr/local/lib
All compilation went OK, but I got a few link errors in the end. The hardest one to solve is the following:
dist\build\src\cpp\eljlog.o:eljlog.cpp:(.rdata$_ZTV6ELJLog[vtable for ELJLog]+0x20): undefined reference to `wxLog::DoLog(unsigned long, char const*, long)'
The corresponding source code is in wxc/src/cpp/eljlog.cpp:
class ELJLog : public wxLog
{
private:
TLogFunc func;
void* EiffelObject;
protected:
virtual void DoLog(wxLogLevel level, const wxChar *szString, time_t t)
{
wxString s(szString);
func (EiffelObject, (int)level, (void*)&s , (int)t);
}
....
I couldn't figure out what caused this error and how to fix it. I did some search about this vtable issue, and some suggested that this is caused by declaring a virtual function in a child class without defining it. Others suggested that it's the order that object files are given on the g++ command line. But neither seems to be the case here.
I tried removing the function ELJLog::DoLog function or commenting out the virtual keyword. Strangely, there is always a link error/errors saying something about vtable for ELJLog, and refers to wxLog::DoLog, even when there is no occurrence of DoLog.
Also, as a side note, wxLog::DoLog seems to be missing in the wxWidgets 3.0 documentation. I am not sure whether this function is deprecated or not. But still, it's causing errors for legacy derived classes in a way that I can't understand.
Any ideas what's going on here?
--- EDIT2 ---
If I comment out the function in question
virtual void DoLog(wxLogLevel level, const wxChar *szString, time_t t) ...
I got different link errors as follows:
dist\build\src\cpp\eljlog.o:eljlog.cpp:(.rdata$_ZTV6ELJLog[vtable for ELJLog]+0x
20): undefined reference to `wxLog::DoLog(unsigned long, char const*, long)'
dist\build\src\cpp\eljlog.o:eljlog.cpp:(.rdata$_ZTV6ELJLog[vtable for ELJLog]+0x
24): undefined reference to `wxLog::DoLog(unsigned long, wchar_t const*, long)'
collect2: ld returned 1 exit status
--- EDIT ---
I worked on this under mingw32 from mingw.org. I built wxWidgets 3.0.0 stable release from source, and the stpes I did were as follows:
per http://mingw.5.n7.nabble.com/win32api-version-4-td32288.html :
edit line 2217 of /c/mingw/{,mingw32/}include/commctrl.h to read
#define TV_DISPINFO NMTVDISPINFO
instead of
#define TV_DISPINFO __AW(NMTVDISPINFO)
The above was needed to fix a MinGW32 4.8.1-4 issue. Then,
./configure --enable-stl --disable-shared
make
make install
./configure --enable-stl
make
make install
mv /usr/local/lib/wx*.dll /c/mingw/bin/
It seems a definition for
virtual void DoLog(wxLogLevel level, const char *szString, time_t t)
is missing in the subclass ELJLog of wxLog. Adding the following copy of DoLog differing in the interface only solved the problem:
virtual void DoLog(wxLogLevel level, const char *szString, time_t t)
{
wxString s(szString);
func (EiffelObject, (int)level, (void*)&s , (int)t);
}
Seeing your build steps now, I don't understand why do you build both the static and shared versions of the libraries. Do you really need both of them? Usually just one (typically shared/DLL when building extensions) is enough. If you do need both, you really should build them in different build directories to avoid weird build issues due to having the files from the old build. So I'd advise to do the following:
Entirely delete your existing sources.
Get them anew (and apply the MinGW fix).
Create build_shared subdirectory and run ../configure && make && make install there.
If this is not enough, i.e. if you really need the static libraries too, create build_static subdirectory of the top level sources directory and run ../configure --disable-shared && make && make install there.
If anything goes wrong in the future, you can always just do rm -rf build_whatever and create a new build directory and rebuild there (cd build_whatever && make -s clean works also, but rm -rf is more satisfying).
Original answer below: it can still be useful to somebody else but it doesn't seem to apply in your case.
One possibility is that you built wxWidgets without 2.8 compatibility. It is on by default, so check that you didn't use --disable-compat28 configure option (I guess this is under Unix?).
If wxLog::DoLog() is actually there in the library (you could use nm or objdump to check this), then I'd check for the use of obsolete g++ #pragma interface and #pragma implementation pragmas as they can result in such breakage IME. If you do find them anywhere, just remove them completely (but remove both of them, otherwise you are certain to have link errors).
I'm a beginner to c++ and JNI and I want to call a Java methode from my C++ program.
When compiling (with Eclipse) I get the following error:
undefined reference to '_imp__JNI_CreateJavaVM#12'
I searched for this problem and came across this post
There the answer was, if I get that right, including the jvm library to the compiling command. Since I'm not compiling by hand I'm not sure how I can make Eclipse do this. Could somebody explain that step by step for a complete beginner?
Here is the code, in case the compiling command won't change anything and the code has some errors.
In this part the error is displayed when calling JNI_CreateJavaVM:
JNIEnv* create_vm(JavaVM ** jvm) {
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options;
/*
* The following is a little messy, but options.optionString wants a char* not a string
* So I convert the String-path to a char-array
*/
string stringPath = "-Djava.class.path=C:\\Users\\Chris\\workspacejava\\PP\\src\\Tests"; //Path to the java source code
int sLen = stringPath.length();
char javaPath [sLen + 1];
int i = 0;
for(; i < sLen; i++)
{
javaPath[i] = stringPath[i];
}
javaPath[i] = '\0';
options.optionString = javaPath;
vm_args.version = JNI_VERSION_1_6; //JDK version. This indicates version 1.6
vm_args.nOptions = 1;
vm_args.options = &options;
vm_args.ignoreUnrecognized = 0;
int ret = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args); //This call results in the error: undefined reference to '_imp__JNI_CreateJavaVM#12'
if(ret < 0)
printf("\nUnable to Launch JVM\n");
return env;}
And here I call this function:
int main(int argc, char* argv[])
{
JNIEnv *env;
JavaVM * jvm;
env = create_vm(&jvm);
if (env == NULL)
return 1;
...
int n = jvm->DestroyJavaVM();
return 0;
}
Further Informations: (I don't know if they help)
I use Windows 7. Both Eclipse and JDK are 64Bit. I'm using MinGW GCC to compile my code.
I'm glad for every piece of advice
That's right, you need to add the jvm library to your build.
Open the project properties dialog.
Select C++ Builder > Settings on the left.
Select the Tool Setting tab.
Select MinGW C++ Linker > Libraries.
Add jvm in the Libraries section.
Add the path to your JDK lib folder in the Libraries Search Path section.
I have a JAVA_HOME environment variable pointing to a JRE subfolder of a JDK so I enter the search path like this: "${env_var:JAVA_HOME}/../lib", with quotes because the environment variable expands to a path with spaces in it.
Now, you might have 32-bit and/or 64-bit JDKs installed. Be sure to use files from the same bit-ness as your compiler output. That includes running your exe with the right jvm.dll first on the DLL search path. On 64-bit Windows, the 32-bit JDK is usually installed under C:\Program Files (x86)\Java....
The #12 says that your compiler is producing 32-bit code (the arguments to JNI_CreateJavaVM are 3 pointers of 4-bytes each) so the linker needs the 32-bit version of jvm.lib rather than the 64-bit version.
BTW—Your java.class.path looks a suspicious for two reasons:
Tests looks like the name of a class. The class path should be a ;-separated list of paths to the root folder of packages. If Tests is a class in the default package, just lop off Tests from your class path.
Eclipse usually sets up Java projects with separate source and binary folders. The paths in the class path are where java should search for .class files. If your project is configured to compile .java files from the src folder to .class files in the bin folder, then replace src with bin in your class path.
I'm trying to compile an run a very basic program given below (test.cpp) which calls the OpenNI class. You can see the files and dirs they're in here. Sorry that some characters screws up a little bit in the browser's encoding. I'm using the linux command: tree, if you know a better command tell me and I will update it.
File Structure
I'm following the guide here, see "GCC / GNU Make".
#include < stdio.h >
#include < OpenNI.h >
using namespace openni;
int
main ( void )
{
Status rc = OpenNI::initialize();
if (rc != STATUS_OK)
{
printf("\nInitialize failed\n%s\n", OpenNI::getExtendedError());
return 1;
}
printf("Hello, world!\n");
return 0;
}
Here is what I'm running in the command line to compile it (gcc 4.7.2):
gcc test.cpp -I../OpenNI-2.0.0/Include -L/home/evan/Code/OpenNi/Init -l OpenNI2 -o test
This works fine but when I run ./test I get the following error:
Initialize failed
DeviceDriver: library handle is invalid for file libOniFile.so
Couldn't understand file 'libOniFile.so' as a device driver
DeviceDriver: library handle is invalid for file libPS1080.so
Couldn't understand file 'libPS1080.so' as a device driver
Found no valid drivers in './OpenNI2/Drivers'
Thanks, any help would be much appreciated.
Instructions from your guide says, that
It is highly suggested to also add the "-Wl,-rpath ./" to your linkage command. Otherwise, the runtime linker will not find the libOpenNI.so file when you run your application. (default Linux behavior is to look for shared objects only in /lib and /usr/lib).
It seems you have exactly this problem -- it can not find some libraries. Try to add proper rpath (seems to be /home/evan/Code/OpenNi/Init/OpenNI2/Drivers in your case) to your compilation string.
I had the same issue after compiling this little "Hello World" with Eclipse and trying to run it in the command line.
The "Wl,-rpath=./" thing did not work for me.
As also discussed here it worked for me after setting some env. variables before execution:
export LD_LIBRARY_PATH="/path/to/OpenNI2:$LD_LIBRARY_PATH"
export OPENNI2_DRIVERS_PATH="/path/to/OpenNI2/Drivers"
export LD_LIBRARY_PATH="/path/to/OpenNI2/Drivers:$LD_LIBRARY_PATH"
Somewhere I got the info that the first two lines should be enough but it was the third line which is important. I does also work just with the third line.
I'm trying to compile and run the app, which was created 4 years ago. It was developed for Windows in Embarcadero RAD Studio C++ builder. Now I try to compile and run it in Windows in VirtualBox using the latest version of RAD Studio. I have a system call to another app in my app:
system("dot.exe -Tjpg -o nfa.jpg NFA_graph.txt");
It keeps returning 1 and the file is not created. I also tried
system("Echo %CD% >> z:\log.txt");
and the file is not created. I also tried like this:
FILE *fpipe;
char *command = "Echo %CD% >> z:\log.txt";
char line[256];
if (0 == (fpipe = (FILE*)_popen(command, "r")))
{
perror("popen() failed.");
exit(1);
}
while (fread(line, sizeof line, 1, fpipe))
{
ShowMessage(line);
}
_pclose(fpipe);
And nothing I get. I wonder if the reason of such strange behaviour is that I'm running this all in VirtualBox?
You're not escaping your \ characters. You should use / in file paths, or \\ if you must. In addition, Windows 7 won't let you write to the root directory of a hard drive w/o administrator access.
To determine if a command environment is available, first do this:
if (!system(NULL)) {
// Can't make any system() calls
}
If your command environment is available, then you need to fully specify the path, making sure to escape the \'s like I mentioned above, and don't write anything to a drive's root directory. Also make note that opening files does not default create directories.
No, it's very unlikely. I see few issues with your code: you did not check errno if system() returns 1. It can help you to spot a real problem. Also, all backslashes must be Esc'ed.
I'm suggesting that dot.exe is not in PATH environment variable, that's the reason of the system() failure.