this is a weird one. i have a -pre-compile target in my custom_rules.xml. in here, some JARs get copied into the libs folder.
if i do a clean build, it fails at runtime because those libraries do not get included in the .apk. looking at the output of ant -v ..., Dx is not processing those libs. so, while the project is being compiled against against those libraries, they are not included at the Dx phase.
if i subsequently do a non-clean ant debug, everything is fine, as the JARs copied by -pre-compile were already there at the start of the build.
any ideas what i'm doing wrong?
i eventually figured this out by painstakingly adding echo statements to the .../tools/ant/build.xml from the SDK.
the path that includes the libraries in .../libs for Dx is defined in the -setup task. this is in the chain before -pre-compile or -pre-build, so if you copy JARs into your .../libs folder at either of those points, it's too late.
i ended up overriding the -setup task, as so,
<target name="-setup" depends="-prepare-libs, android_rules.-setup"/>
<target name="-prepare-libs">
... build / copy libs in to .../libs here
</target>
note the syntax for calling through to the overridden -setup task ... the project name defined in the project tag appended with the task name, as defined in the build.xml imported from the SDK.
Related
For a project, I am using Android gradle scripts with CMake, gradle plugin is version 3:0:0, CMake version 3.6. Both gradle and CMake files are pretty simple and uninteresting (just defining the files used - I can still copy-paste them as required).
I have the following project structure; basically a codebase producing a few tens of .so files (the native part for the Android packages that get packaged into an apk, thereby called 'Executables'), which all depend on the same shared library code (static libraries, thereby called 'Libraries'). The Library code is still (relatively) volatile, so I wish the Executables to have project-level dependencies on them, so that whenever the Executables are built, the Libraries are rebuilt on-demand every time their code is changed.
The structure looks like:
+ LibProjects/
---Bin/ (Originally empty)
---Lib1/CMakeLists.txt (+sources files, same level as the CMakeLists.txt)
...
---Lib10/CMakeLists.txt (same)
+ Executables/
---Executable1/CMakeLists.txt (source files here)
--------------/AndroidFiles/build.gradle (and other android project files)(points to the CMakeLists.txt)
...
---Executable40/CMakeLists.txt
The Libraries' CMakeLists redirect their output into the Bin folder using
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY {CMAKE_CURRENT_SOURCE_DIR}/../Bin/${ANDROID_ABI}/${LibraryName})
The executable's projects add dependencies on the libraries "as normal"
add_subdirectory(${PROJECTS_ROOT}/LibProjects/${LibraryName} ${PROJECTS_ROOT}/Framework/Bin/Android/${ANDROID_ABI}/${LibraryName})...
Everything almost works, in the sense that I can get sensible executables and the Executables trigger builds of the libraries.
The problem is that when building the executables sequentially, each one does NOT reuse the library project outputs of the other ones: When I build Executable1, it will build all libraries (normal) and then it will build itself. Afterwards, when I build Executable2, it will NOT reuse the libraries that were already built for Executable1, and so on - this effectively increases my build time by a factor of ~10.
I can find the output of the build of each library inside the /Bin folder as expected, but they are not reused across executables - there are no CMake "project files" (is this the correct term) in the bin folder, all of them get generated inside the executable build directory.
The problem I am trying to resolve is the build times stemming from the fact that each library gets rebuilt for each executable.
At the moment the solutions I am considering is to somehow instruct CMake to use the Bin folder (or another folder) as a working folder for each library in its own folder instead of with the executable, hoping that the gradle android plugin will be smart enough to then spot that neither the cmakefiles nor the object files need to be regenerated, and avoid the rebuild.
The restriction that I have is that I cannot restructure the codebase itself, and that each Executable must be buildable separately of the others - there is absolutely no possibility of a top-level CMake - each Executable should be able to be triggered on its own.
CMake can guess if the build is up-to-date by reading informations froms the current build directory.
When you run CMake manualy in Executables/<x> directory, cmake retrieve information from the build directory associated to Executable/<x> directory. It then check if the timestamp of the built file correspond to the last build performed in this build directory. If not, it rebuild. What happen is that: Lib1 library file is built after you build Executable1, then you run cmake in Executalbe2, it compares the timestamp of Lib1 target file, see that this file was not produced by this instance of the cmake build and then rebuild the lib. And so on.
So you have two options:
1- Either you build the library and install their target files in the bindirectory (using install cmake command and make install bash command for exemple). Then in the Executalbe<x>/CMakeLists you use find_library command instead of add_subdirectory.
2- Or you create a super project which has the following structure:
+ supper_project
---CMakeLists.txt #add_subdirectory(LibProjects/lib<x>)... add_subdirectory(Executables/Executalbe<x>)...
+ LibProjects/
---Bin/ (Originally empty)
---Lib1/CMakeLists.txt (+sources files, same level as the CMakeLists.txt)
...
---Lib10/CMakeLists.txt (same)
+ Executables/
---Executable1/CMakeLists.txt (source files here)
--------------/AndroidFiles/build.gradle (and other android project files)
(not any more:points to the CMakeLists.txt)
...
---Executable40/CMakeLists.txt
I managed to work around this problem - but in the end it was by working around rather than with CMake.
I removed the CMakeFile-level dependencies (add_subdirectory) and only left the libraries at the linking level (target_link_libraries Executable [the library files])
Afterwards, I created gradle scripts for each library and added dependencies to these scripts in each application gradle script, so that the building of the libraries gets triggered by gradle dependencies instead of CMake dependencies. It's slower than it would be if gradle could be avoided, but much faster than rebuilding every time, and the overhead is at least constant (a few seconds per project).
I think problem lies in the way you have defined your dependencies.
For each executable you are creating separate targets using add_subdirectory.
e.g. for executable 1 you have add_subdirectory(${PROJECTS_ROOT}/LibProjects/${Library1}) and for executable 2 also you have add_subdirectory(${PROJECTS_ROOT}/LibProjects/${Library1}), so cmake will create two separate targets for same library1 in each of the executable's subdirectory and thus it will create separate timestamp and cache files. That is why it looks that it is building the same library for multiple times, but in fact for cmake they are different targets.
To fix this you can include all libraries in top level CMakeLists.txt using add_subdirectory and them in each executable's CMakeLists.txt add the dependency using add_dependencies command.
With respect to this question, simply putting a jar into the /libs does not auto-magically include that jar into the .dex when invoking, say, ant debug. Not at least with Android SDK ver 15.
I've verified this by comparing the same project created two different ways. First (call it 'Alpha'), by Eclipse. Second, via android create project ..., blah blah blah (the Ant way, call it 'Bravo').
Both Alpha and Bravo I built using ant debug. Comparing their /bin dirs, the jar under <project_root>/libs is missing from Bravo's *.d; Alpha's aren't.
What magic is Eclipse embedding during project creation?
Better still, how can I ensure a jar is passed to ant debug|release when building a project, that a jar is included in the endstate?
You may just have to adjust the build.xml to include something like the following in the -pre-build node if you want to hardwire it in. You can also add this in a custom target in the build.xml file that would able you do include from the command line when you want. Something like the following could work.
<target name="add-jar">
<copy file="${src.folder}/YourJarHere.jar" tofile="libs/YourJarHere.jar" overwrite="true"/>
</target>
Where ${src.folder} is defined in your ant.properties file.
Something like src.folder=PATHOFYOURJAR
Then you should be able to run
ant debug add-jar
including the file.
I have had to manually create the libs folder in the past but I don't see why you can't do this through the build.xml file. Hope this helps!
I am managing and running my android app from command line without using ant, I followed these steps:
generate R.java
compile R.java and all .java files in src to .class files
assembling set of class files into dex file using the command below
dx --dex --verbose --output=./bin/classes.dex ./bin
.class files are in bin directory.
But I'm getting the following errors in these steps:
java.lang.Runtime exception:.\bin file not found
at com.android.dx.cf.direct.ClassPathOpener.process
at com.android.dx.command.dexer.Main.processOne
at com.android.dx.command.dexer.Main.processAllFiles
at com.android.dx.command.dexer.Main..run
at com.android.dx.command.dexer.Main.main
at com.android.dx.command.Main.main
Due to this, I'm unable to create the Classes.dex file.
Can someone suggest a solution for this?
[not using eclipse and ant only through command line]
If you need to "manage your Android projects from command line", when you should use Ant build.
Ant's build.xml is a official standardized way to build Android projects. Ant scripts can do anything you may need to build your project.
If you want most modern build tools for Android, you can look at Gradle for Android projects. Note: today it's still in alpha stage.
Try entering the full path instead of the relative path.
Also you must put the class files inside a directory named exactly like it's package name. for example for com.test.me.MyActivity you must use com/test/me/MyActivity.class
And since we are on the topic, remember that dx can only work with class files created using Java6 (or less) so if you are using java7 to compile your code, add "source 1.6 target 1.6" parameters to your command line.
I maintain an Android app and am not using Eclipse. I am not using Eclipse. I am using ant and build.xml and build.properties.
I have places my .jar file into the libs/ directory. My code compiles just dandy. But when I run it on the emulator, the output APK does not include the .jar, so I get a runtime stacktrace:
ERROR/AndroidRuntime(470): java.lang.NoClassDefFoundError: com.google.ads.AdView
my build.properties looks like this:
jar.libs.dir=libs
And the libs/ directory contains my .jar file.
What needs to be in build.xml so that the external .jar file is included in the APK?
Edit: In theory this answer should work, but it doesn't for me. Is it out of date? What gives? How to add external jar libraries to an android project from the command line
I just came over a similar problem and noticed that libraries should not be placed in "myprojectdir\lib". When I moved them to "myprojectdir\libs" everything started to work.
It turns out that I needed to upgrade the version of ant I was using to 1.8. During the compile process, I had been getting this error message:
Warning: Reference out.dex.jar.input.ref has not been set at runtime,
but was found duringbuild file parsing, attempting to resolve. Future
versions of Ant may support referencing ids defined in non-executed
targets.
I googled it, and found that I needed to upgrade Ant, and now I don't get this warning, and my application does not force close.
What needs to be in build.xml so that the external .jar file is included in the APK?
Just putting it in libs/ is sufficient.
my build.properties looks like this:
That line should not be necessary. It does not appear in my build.properties files that build successfully with JAR files.
If you use dexdump -f classes.dex from your project's bin/ directory, you will be able to determine whether com.google.ads.AdView made it in there. If it did not, then something is strange with your build scripts. If it did, then perhaps there is a dependent JAR that you are missing (though I would expect a VerifyError in that case).
You use 3rd party library, but you seem didn't run DX on it. Make sure that not only your code processed by DX tool (I assume Ant does it), but also all 3rd party libraries you use. You can look in 7Bee script I use to convert web applications to Android davlik format, so it can work for you too. You can find more about the script on Atjeews page.
Solution:
right click on the project in project tree and select Project
properties
select Java Build Path
select TAB Order
and Export
check GoogleAdMobAdsSdk-4.0.4.jar (or your
version SDK)
press OK
clean project by menu Project
-> Clean
rebuild project (Project – Build Automatically)
I have an existing project that builds fine using my IDE. I'd like to use the "android update" command to generate an ant buildfile for this project.
The buildfile is generated fine, but the build fails because it's not building with some jarfiles I have in my libs directory.
I'd like to figure out the proper way to tell ant to build with some external jar files in my libs directory. How should I do this? Is it a property in build.properties? Do I need to modify build.xml somehow? Or is there a different solution entirely?
but the build fails because it's not
building with some jarfiles I have in
my libs directory.
And your error message is...what? I suspect you may be misinterpreting the error message.
I'd like to figure out the proper way
to tell ant to build with some
external jar files in my libs
directory. How should I do this?
Just put them in libs/, as Ant will add everything in there to your build path. See this project, and this project, and this project for examples.
I spent some time trying to get the Facebook API to work with ant. The trick for me was to add this to my default.properties files.
android.library.reference.1=../Facebook
Where ../Facebook contains AndroidManifest.xml, etc. The real key being the relative path. Don't use an absolute path because Ant seems to treat your project directory as the root.
This should hold true for other library projects that you are including from source code.
I was dealing with similar issue. I'm building Android project on Jenkins using standard Ant build.xml (generated by Android SDK). I also have reference to another Java project with some shared domain classes. In Eclipse there is no problem with it. The domain project is a project reference. However on Jenkins this domain.jar is built by Maven and it was not accessible by Android project.
I have finally solved it by adding this at the end of build.xml:
<target name="-pre-build">
<copy todir="${jar.libs.dir}">
<fileset
dir="../path-to-another-project/target"
includes="*.jar" />
</copy>
</target>
This copies all jars from the target directory of another project into "libs" directory of my Android project. The -pre-build Ant target is automatically called before Android compilation starts.
I agree with Mark, however, if you're planning to modify your build script further - than you need to make it custom. Bring tasks from android/platforms/android-PLATFORMVERSION/templates/android_rules.xml to your build.xml and modify whatever you want to modify. Including location for external libs.