"Referenced from" errors when building with j2objc - java

I'm seeing a lot of errors, upwards of 170, when building my j2objc integrated project.
I think the java j2re library is correctly being located and the linking step says
-Llib/j2objcDist/lib
-Llib/j2objcDist/lib/macosx
-F/Users/username/Library/Developer/Xcode/DerivedData/MyApp-dkbwtvvwogkqknfpbozsmzhgrcei/Build/Products/Debug-iphonesimulator
-Flib/j2objcDist/frameworks
A lot of the paths that I'm seeing include the full user path but on the lib/j2objcDist/lib paths.
My library search paths are
${PROJECT_DIR}/lib/j2objcDist/lib/
My header search paths are
${PROJECT_DIR}/lib/j2objcDist/include
${DERIVED_FILES_DIR}
${PROJECT_DIR}/lib/j2objcDist/frameworks/JRE.framework/Headers
${PROJECT_DIR}/lib/j2objcDist/lib
My framework search paths are
${PROJECT_DIR}/lib/j2objcDist/frameworks
I've replicated the settings in the demo app available on the j2objc.org site to be best of my knowledge.
Any suggestions on what to try or where to look to fix this would be great.

It looks like you've set it up correctly for where to find the libraries, but haven't told the linker to include any libraries. In Other Linker Flags, set either "-ljre_emul" (or "-l jre_emul") to tell the linker to include the JRE emulation library.
That will fix all the errors you listed, but if you use other libraries then they need separate -l flags. For example, if you use any Google Guava classes, then "-lguava" also needs to be specified.
The linker finds libraries by taking each -l argument and converting it into a library name ("lib" + arg " + ".a", or libjre_emul.a in this case). It then checks each -L path to find this file, so the library should be listed with "ls ${PROJECT_DIR}/lib/j2objcDist/lib/libjre_emul.a" (substituting the actual project directory, of course).

If there is a -ljre_emul flag and a valid -L path to that library, then the issue is likely to be using a translator from one J2ObjC release and libraries from a different one. J2ObjC is a compiler, and its generated files need to be treated as transient build artifacts, not permanent source files. If your project saves translated .m and .h files, then every time a new distribution is used, all Java sources need to be updated with new translations.

Related

Decompile JAR, Modify it, Recompile again?

I have an older Jar file which I have to modify in order to get it to work.
I have already decompiled it with jd-gui and changed the parts that needed change. I would now like to know what I have to do in order to get a jar back?
I guess that I have to add the libraries, but there is no extra lib directory.
How do I put everything together?
#Stephen C
"Therefore, when you make your changes and recompile, the resulting ".class" file could have unexpected "
How exactly is this relevant? I only want the function of the Jar file and not a 1:1 copy of it.
The Jar file is unsigned. What exactly would be the reason to sign a Jar file anyway? If I start it from another program?
If you are missing dependencies after decompiling the entire jar, that could mean the jar did not include them. When you create a jar, you can choose not to include dependencies in it, but this assumes that they will be available on the classpath at runtime. Check if there are any relationships with other jar files on the classpath when you run the original jar. See this answer for details on how to achieve this. Once you have identified all the dependencies, you can easily compile the jar from an IDE such as IntelliJ/Eclipse or from command line.
As a side note, if the changes you would like to make to the jar are minor or isolated I recommend editing the bytecode (much easier for small edits). I prefer this bytecode editor.
If decompilation fails on some parts of the code, the functionality of the jar will not be restored upon recompilation. In this case, instead of going through all available decompilers and hoping that you can decompile that code, I suggest you identify the set of classes which you are trying to edit, modify the rest of the classes such that they compile and do not have any side effects on the classes which are of interest to you (do not delete anything that is referenced by these) and compile the jar (even if this isn't the jar you want). You can then extract only the class files which you wanted to modify from the jar, and overwrite them in the original jar. This will only work if your changes didn't have any side effects.
If you are asking how to create a JAR:
You can do it using a build tool such as Maven, Gradle, Ant and so on.
You can do it using a Java IDE
You can do it using the command line jar tool; see How to create a JAR file from the official Oracle Java tutorials.
But it there is no guarantee that what you are doing will actually work. Here are a couple of the problems.
If the original JAR file was signed, you won't be able to re-sign the new JAR ... unless you have the private key that was used when signing.
Decompilation is often inaccurate. There is no guarantee that the Java code that it produces is a correct representation of the original class. Therefore, when you make your changes and recompile, the resulting ".class" file could have unexpected / unwanted differences relative to the original.
I guess that I have to add the libraries, but there is no extra lib directory.
I'm not sure what you mean by that. The (new) dependencies of the JAR don't necessarily need to be in the JAR itself. It depends on what kind of JAR it is; e.g. is it a so-called "executable" JAR that you launch using java -jar my.jar ....
Use jar plugins for gradle or maven for example, or build it with intelliJ, here's an answer in another post: How to build jars from IntelliJ properly?
Since I had trouble getting the .jar file completely recompiled and working with my application, I wanted to share here the steps that were missing in the previous answers.
In my specific case, to make things as easy as possible, I wanted to only modify one .java file in the result of the decompilation and update it directly in the .jar file.
I started from the answer from Paulo Ebermann on a similar question, and I ended up with:
javac -source 8 -target 8 -d classdir -cp \
"\
path/to/dep1.jar; \
path/to/dep2.jar; \
path/to/myoriginal.jar \
" path/to/my/java/class.java
cd classdir
jar -uf path/to/myoriginal.jar path/to/my/java/class.class
Notes:
the path/to/myoriginal.jar which is in the path of the dependencies, this forces the java compiler to look for missing classses in the original .jar file rather than in the local decompiled code (which would require recompilation and more dependencies) and therefore I have intentionally left out the . path in the list of class paths
the -source 8 -target 8 which were required to force the class to compile for the appropriate version of the runtime machine.
the -uf which indicates that the jar tool should only update the file with the provided class

Configuring libmediainfo to work with Java project without installation across all platforms (OSes)

I am using mediainfo (http://mediainfo.sourceforge.net/en) to extract information from audio and video files using Java code.
My java project runs over all platforms (osx, win & linux). So far I have only tested mediainfo over osx where the procedure is simple: just put libmediainfo.dylib in the target folder and access it using a native library and you're good to go. And the solution works flawlessly...
I am now looking to expand this functionality to the other OSs, starting with Linux. However, it is proving to be more of a challenge than I thought.
At first I kept getting this:
"java.lang.UnsatisfiedLinkError: Unable to load library 'mediainfo': libmediainfo.so: cannot open shared object file: No such file or directory"
and this was expected as it was looking in /usr/lib
but this was solved by installing the suitable libmediainfo0 & libzen0 ".deb from http://mediainfo.sourceforge.net/en/Download/Ubuntu
Still, my solution needs to be portable, meaning, I want all necessary resources to be included with the java project package without requiring any further installations.
I also need to know if it's possible to change mediainfo to look for the resources in my java package instead of a system location.
For your reference, I am using Java Native Access (jna) to interact with the library. Also using the MediaInfo.java & MediaInfoLibrary.java classes that the website suggests.
Let me know if you need other details.
any wisdom is highly appreciated
thanks!!
The latest release of JNA (3.5.2) will automatically unpack native libraries bundled as resources (whether file- or jar-based).
If you include you shared library for linux/amd64 as /linux-x86-64/libmylibrary.so in one of your jar files, JNA will extract it and load it automatically when you call Native.loadLibrary("my library"). Older versions of JNA require that you make the library available on LD_LIBRARY_PATH (envariable) or jna.library.path (system property).

GWT project and Eclipse linked resources

I have to use a Javascript file in my GWT Project. This Javascript is in a common library project and I deploy it together with my GWT Project using ANT.
So, I have no problem in production environment: but I cannot test it in development phase.
I tried to create an Eclipse link to Javascript resource but seem that GWT "can't see it".
Some behavior with other kind of resources (images, css etc.).
Is it a bug or is there another way to do?
I'm using Eclipse Juno, GWT 2.5.0 and Debian 7.0.
Thank you.
Can you just use script tag in your project's .html file?
If you're using some kind of source control, it usually has a way to make a link to a dependent project or file. Simply include that link in your GWT Project, and reference the file through there.
If you can't or don't want to do it through your source control, do it through your OS. Since you're using Linux, simply make a symbolic link to the common file/folder using ln -s (if you were using Windows, you'd need to run mklink from the command line), and reference the file that way.
In either case - source control or OS - you'll be able to see the file(s) when you refresh your project in Eclipse, and modifying one will modify the other in its own directory.
Edit - information on symbolic links in CVS
I haven't played with CVS in quite some time, so can't speak much about its capabilities for symbolic links. A bit of googling said it's not supported, though there are workarounds. One workaround is to add script files that run during checkout. That sounds like it may still be tough to make OS-agnostic. I did find one site that mentioned using module aliases to get the same result. Maybe that will give what you need. An excerpt from the site follows:
One common way to handle situations like this in CVS is to alias the
collection in a modules file rule. -Checkout the "CVSROOT" module and
you'll find the "modules" file; simply change it and check it in like
anything else, with the exception that when you check in CVSROOT files
they "activate" at the same time. The example below may look a little
kludgy, and it is because AFAIK you can't redefine a directory and alias
it at the same time, sadly. I'll use a typical Java situation as its
package system lends itself well to this kind of thing:
Real module directories are "a", "b", and "common"
Directory alias for all common srouce
_common_src_all -d src/com/mycompany/common common/src/com/mycompany/common
Full "A" project including common
a_all &a &_common_src_all
Full "B" project including common
b_all &b &_common_src_all

How to add directory to Clojure's classpath?

I have installed the libraries with Maven to the ~/.m2/repository/ directory. I would like to add that path to the default Clojure classpath. I could not find the documentation how to do that.
Any hints?
Cheers!
clj
Clojure 1.4.0
user=> (require '[clojure.java.jmx :as jmx])
FileNotFoundException Could not locate clojure/java/jmx__init.class or clojure/java/jmx.clj on classpath: clojure.lang.RT.load (RT.java:432)
The class path by default is:
user=> (println (seq (.getURLs (java.lang.ClassLoader/getSystemClassLoader))))
(#<URL file:/Users/myuser/cljmx/> #<URL file:/usr/local/Cellar/clojure/1.4.0/clojure-1.4.0.jar> #<URL file:/Users/myuser/cljmx/>)
nil
Leiningen really makes this process a lot less painful by keeping the setting of the classpath associated with the project, and more importantly leads to a repeatable build process. where you can come back to the project years later and still get a repl. A general outline of using leiningen in these cases:
lein new projectname
add the library you need to your project.clj file with a name you choose
run lein deps to print out the command to use to add the jar to your local repo
add the jar
run lein deps again (you can skip this step if using leiningen2)
run lein repl
enjoy
this is assuming that the library you are using is not already part of or available from a package in a maven repo, which many are.
The non-painful, popular method is to not mess with maven and classpaths and the JRE directly and use leiningen: https://github.com/technomancy/leiningen/
Otherwise, you can modify whatever is in clj and add/set the classpath in whatever ways java likes. See for example Setting multiple jars in java classpath
It should be noted that you also have the option of adding classpaths at runtime with the library pomegranate https://github.com/cemerick/pomegranate
This lets you do like:
(require '[cemerick.pomegranate :as pom])
(pom/add-classpath "/home/user/~.m2/....")
I assume that clj is a script to start Clojure REPL. Take a look into this script and find line similar to this:
java -cp /path/to/clojure.jar clojure.main
Here you start class clojure.main having "clojure.jar" on your classpath. To add more jars just add them to the end of -cp option values. E.g. on Linux:
java -cp /path/to/clojure.jar:/path/to/mylib.jar clojure.main
(use ; instead of : on Windows)
However, very soon you'll get tired of this way and will look for project management tool. So it makes sense to start using it right now. Take a look at Leiningen - it manages dependencies for you based on Maven (so it will be extremely easy to add new jar) and has REPL.
Another option is to create a deps.edn file in the folder where you plan to run the REPL or where you keep your project files.
This file is used to inform Clojure about dependencies, source files, execution profiles, etc… It's loaded when you run a REPL (but there are other use cases) and it's supported by the core of Clojure and it's officially documented on https://clojure.org/reference/deps_and_cli
In your case you may just want to put something like the following, to declare what dependencies you want to download and put on the Java classpath.
{
:deps {
the.dependency/you-want {:mvn/version "1.0.0"}
}
}
In deps.edn you can specify:
third party dependencies (eg JARs) that can be already saved locally, or hosted on a Maven repository, or on Git repository…
source paths, where your source code resides, if any
Note that the dependencies will be downloaded and cached in .cpcache/ folder, beside the deps.edn itself. I'm not sure if you can instruct it to use the global ~/.m2 instead.
You may find the dependency coordinates (name and latest version) on clojars.org
deps.edn is "lighter", part of the core Clojure, if less powerful than leiningen; so maybe suited for setting up an environment for casual/exploratory coding at the REPL or CLI.
You can also have a global deps.edn in ~/.clojure/deps.edn where you may want to define common configurations, dependencies, etc. to be used across different projects. Specific configurations can be invoked/overridden using options on the command line.

Matlab Compiler MCC errors on imports for Java classes from dynamic Java classpath

How can I get mcc to recognize imports from user-provided Java libraries, or to simply ignore unresolvable imports?
I have a Matlab codebase that I'm building with the Matlab Compiler, but the build is breaking because mcc is erroring out when it encounters import statements for Java classes that were in JARs on Matlab's dynamic classpath. I am including all the JAR files on the classpath with the mcc -a option. The code works in the IDE, and I think it will work in the deployed app, if it will only allow me to build. (Works under R2009b, which ignores these imports in non-MCOS classes.)
Here's a simple repro. This file is in the same dir as guava-11.0.1.jar from Google Guava.
%file hello_world_with_import.m
function hello_world_with_import
import com.google.common.base.Stopwatch;
disp('Hello, world!');
end
Running it in Matlab works fine. But building it fails. (The javaaddpath here is not strictly necessary in the example, because bad imports by themselves are not an error in plain Matlab. Just showing how it works in practice, and how I wish mcc picked up on it.)
>> javaaddpath('guava-11.0.1.jar');
>> hello_world_with_import()
Hello, world!
>> mcc -m -a guava-11.0.1.jar hello_world_with_import
Error: File: C:\Temp\import_test\hello_world_with_import.m Line: 3 Column: 8
Arguments to IMPORT must either end with ".*"
or else specify a fully qualified class name: "com.google.common.base.Stopwatch" fails this test.
Unable to determine function name or input/output argument count for function
in MATLAB file "hello_world_with_import".
Please use MLINT to determine if this file contains errors.
Error using mcc
Error executing mcc, return status = 1 (0x1).
This is in Matlab R2011b on Windows.
Some background on my environment. My app has about 40 JARs on the dynamic classpath which are a mix of third party libraries and our own Java code. It's deployed to 50+ users on a mix of single-user and multi-user Windows machines. And there are other groups that may be deploying other MCR apps to the same users and machines. On any machine, different MCR apps may be run concurrently by the same or different users. We do weekly releases, and (mostly due to changes in our own Java code) at least one JAR file changes about every other release. I need a mechanism that will work in this environment.
Any suggestions? Anybody know a good way to get mcc to add stuff to its java classpath in the compilation step, or just ignore bogus imports? My fallback plan is to go through the codebase and remove all the imports for Java classes, which is kind of a pain.
UPDATE 12/2/2012: I heard from MathWorks that this is fixed in Matlab R2012b. (But I'm no longer using Matlab so can't personally verify it.)
UPDATE 12/09/2014: I'm using Matlab again (R2014b), and the Matlab Compiler now includes JARs that are on the dynamic classpath in the compiled program's dynamic classpath. It doesn't seem to automatically include the JAR files in the archive, though; you must manually include them using an mcc command line switch, or adding them as "additional included files" in the Matlab Compiler app.
The code executing in the MATLAB IDE works because the guava jar file has been added to the "dynamic" classpath via the javaaddpath method. However, when you use MCC to invoke the MATLAB Compiler, it does not rely on the dynamic java classpath, but the "static" java classpath which is defined in:
$MATLABROOT/toolbox/local/classpath.txt
If you add an entry for your JAR file here, then MCC will be able to resolve the IMPORT line in your M-File.
So to test this, I downloaded the guava jar file and tried the steps above. Works like a charm.
Also, If you read the "Troubleshooting" section for the MATLAB Compiler, this exact situation is documented:
http://www.mathworks.com/help/toolbox/compiler/brtm1xm-8.html
Quoting from the link: "The import statement is referencing a Java class () that MATLAB Compiler (if the error occurs at compile time) or the MCR (if the error occurs at run time) cannot find.
To work around this, ensure that the JAR file that contains the Java class is stored in a folder that is on the Java class path. (See matlabroot/toolbox/local/classpath.txt for the class path.) If the error occurs at run time, the classpath is stored in matlabroot/toolbox/local/classpath.txt when running on the development machine."
You just have to put import statements in a separate .m file.
so from:
javaaddpath 'c:\some.jar';
import com.something.Element;
...interesting stuff...
There will be a do_imports.m:
import com.something.Element;
And in original .m:
javaaddpath 'c:\some.jar';
do_imports
...interesting stuff...
And then it will compile and work. No need to mess around with system-wide classpaths.
Here is an extract from the link
http://blogs.mathworks.com/desktop/2009/07/06/calling-java-from-matlab/
MATLAB maintains a path for Java classes separate from the search path. That means even if you have a .class or .jar file on the MATLAB path, unless you use javaaddpath you will not be able to use it. To see what is currently on the path use javaclasspath. Running this command you will show you a long list of files that ship with matlab called the Static Class Path and then you'll see the Dynamic Class Path. The dynamic class path is where classes added to the path with javaaddpath will be placed. They can be removed with javarmpath and have to actively reloaded each session of matlab.

Categories