Skip to content

Commit

Permalink
Implements android build.
Browse files Browse the repository at this point in the history
  • Loading branch information
lev-k committed Sep 16, 2016
1 parent 62ad25c commit 8bed77a
Show file tree
Hide file tree
Showing 8 changed files with 456 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ debian/tmp/
obj-x86_64-linux-gnu/
debian/files
debian/libapngasm/
lib/tmp
5 changes: 5 additions & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ ADD_LIBRARY(${APNGASM_DYNAMIC_LIB_TARGET} SHARED
FIND_PACKAGE(PNG REQUIRED)
INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(${APNGASM_DYNAMIC_LIB_TARGET} ${PNG_LIBRARY})
MESSAGE(${PNG_VERSION_STRING})

FIND_PACKAGE(ZLIB REQUIRED)
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS})
Expand Down Expand Up @@ -97,3 +98,7 @@ ENDIF(RUBY)
IF(JAVA)
INCLUDE(${PROJECT_SOURCE_DIR}/interfaces/java/CMakeLists.txt)
ENDIF(JAVA)

IF(ANDROID)
INCLUDE(${PROJECT_SOURCE_DIR}/interfaces/android/CMakeLists.txt)
ENDIF(ANDROID)
56 changes: 56 additions & 0 deletions lib/interfaces/android/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

#Set natives build dir
# TODO change this!
SET(NATIVES_BUILD_DIR ${PROJECT_SOURCE_DIR}/tmp/build/)

#Get required libs/build chain tools
EXECUTE_PROCESS(COMMAND ruby interfaces/android/prepare.rb ${NATIVES_BUILD_DIR}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})

# TODO & TEMPFIX
# Running SWIG through CMAKE doesn't work because CMAKE SWIG is too tied to the base system.
# As a temporary fix the actual compilation is commented out and we're using a postbuild script
# to do the actual SWIG handling; passing SWIG generated interfaces through an android mk project.
ADD_CUSTOM_TARGET(android
ruby interfaces/android/androidbuild.rb ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR} ${NATIVES_BUILD_DIR}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
)

# Jar test
FIND_PACKAGE(Java REQUIRED COMPONENTS Runtime Development)
INCLUDE(UseJava)

SET(SWIG_ANDROID_JAR_TARGET android_jar)
SET(SWIG_ANDROID_JAR_NAME libapngasm-android)
SET(SWIG_ANDROID_JAR_FILENAME ${SWIG_ANDROID_JAR_NAME}-${APNGASM_LIB_VERSION}.jar)
SET(APNGASM_JAVA_FILES
${PROJECT_BINARY_DIR}/japngasm/APNG.java
${PROJECT_BINARY_DIR}/japngasm/APNGAsm.java
${PROJECT_BINARY_DIR}/japngasm/APNGFrame.java
${PROJECT_BINARY_DIR}/japngasm/rgb.java
${PROJECT_BINARY_DIR}/japngasm/rgba.java
${PROJECT_BINARY_DIR}/japngasm/SWIGTYPE_p_p_unsigned_char.java
${PROJECT_BINARY_DIR}/japngasm/SWIGTYPE_p_unsigned_char.java
${PROJECT_BINARY_DIR}/japngasm/APNGFrameVector.java
${PROJECT_BINARY_DIR}/japngasm/APNGJNI.java
${PROJECT_BINARY_DIR}/japngasm/NativeLibLoader.java
)

CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/interfaces/android/src/NativeLibLoader.java.in ${PROJECT_BINARY_DIR}/japngasm/NativeLibLoader.java @ONLY)

ADD_JAR(${SWIG_ANDROID_JAR_TARGET}
SOURCES ${APNGASM_JAVA_FILES}
VERSION ${APNGASM_LIB_VERSION}
OUTPUT_NAME ${SWIG_ANDROID_JAR_NAME}
)
SET_TARGET_PROPERTIES(${SWIG_ANDROID_JAR_TARGET}
PROPERTIES
EXCLUDE_FROM_ALL TRUE
)

ADD_DEPENDENCIES(${SWIG_ANDROID_JAR_TARGET} android)

ADD_CUSTOM_COMMAND(TARGET ${SWIG_ANDROID_JAR_TARGET}
POST_BUILD
COMMAND ${JAVA_ARCHIVE} -uvf ${SWIG_ANDROID_JAR_FILENAME} -C tmp libs/
)
56 changes: 56 additions & 0 deletions lib/interfaces/android/androidbuild.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env ruby

require 'git'
require 'fileutils'

@build_dir = ARGV[0] || Dir.pwd
@source_dir = ARGV[1] || "#{@build_dir}/../../lib/"
@natives_dir = ARGV[2] || "#{@source_dir}/tmp/build/"
@interface_dir = "#{@build_dir}/japngasm/"

puts "== copying natives"
FileUtils.cp_r("#{@source_dir}/interfaces/android/jni", @build_dir, {remove_destination: true})
FileUtils.mkdir_p(@interface_dir)
FileUtils.mkdir_p("#{@build_dir}/libs")
FileUtils.mkdir_p("#{@build_dir}/libs/armeabi")
FileUtils.cp_r(Dir["#{@natives_dir}/natives/lib/arm/*.so*"].collect{|f| File.expand_path(f)}, "#{@build_dir}/libs/armeabi/", {remove_destination: true})
FileUtils.mkdir_p("#{@build_dir}/libs/x86")
FileUtils.cp_r(Dir["#{@natives_dir}/natives/lib/x86/*.so*"].collect{|f| File.expand_path(f)}, "#{@build_dir}/libs/x86/", {remove_destination: true})
FileUtils.mkdir_p("#{@build_dir}/libs/mips")
FileUtils.cp_r(Dir["#{@natives_dir}/natives/lib/mips/*.so*"].collect{|f| File.expand_path(f)}, "#{@build_dir}/libs/mips/", {remove_destination: true})

puts "== Copying NDK build files and modifying variables"
txt = File.read("#{@build_dir}/jni/Android.mk")

# set source path
txt.gsub!("$(OR_INCLUDE_PATH)", "#{@source_dir}/src/ #{@build_dir}/src/ #{ENV["CRYSTAX_NDK"]}/sources/boost/1.58.0/include/ #{@natives_dir}/natives/include/")
txt.gsub!("$(OR_LIB_PATH)", "#{@natives_dir}/natives/lib/")

cpp_files = Dir.glob("#{@source_dir}/src/**/*.cpp")
cpp_files_string = ""
cpp_files.each { |cpp_file| cpp_files_string += "#{cpp_file} " }
txt.gsub!("$(OR_CPP_SOURCES)", cpp_files_string )

File.open("#{@build_dir}/jni/Android.mk", "w") { |mkfile| mkfile.puts txt }

puts "== Creating Native Interface Java sources"
`swig -c++ -java -package japngasm -outdir #{@interface_dir} -o #{@build_dir}/jni/apng_wrap.cpp #{@source_dir}/src/apng.i`

puts "== Running NDK Build"
`NDK_PROJECT_PATH=#{@build_dir} #{ENV["CRYSTAX_NDK"]}/ndk-build`

puts "== for mac (copy the missing file)"

puts "== Copying temporary natives for jar"
Dir.chdir(@build_dir) do
tmp_dir = 'tmp';
FileUtils.rm_rf(tmp_dir);
Dir.glob('libs/**/*') do |filename|
tmp_filename = "#{tmp_dir}/#{filename}"
if FileTest.directory?(filename) then
FileUtils.mkdir_p(tmp_filename)
next
end
FileUtils.cp_r(filename, "#{tmp_filename}_", {remove_destination: true});
end
end
24 changes: 24 additions & 0 deletions lib/interfaces/android/jni/Android.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# File: Android.mk
LOCAL_PATH := $(call my-dir)
OR_LIB_PATH := LOCAL_PATH
OR_INCLUDE_PATH := LOCAL_PATH
OR_CPP_SOURCES :=

include $(CLEAR_VARS)

LOCAL_MODULE := apngasm-android
LOCAL_SRC_FILES := apng_wrap.cpp $(OR_CPP_SOURCES)
LOCAL_CPP_FEATURES += exceptions rtti
#LOCAL_CFLAGS := -frtti -fexceptions
LOCAL_C_INCLUDES += $(OR_INCLUDE_PATH)/$(TARGET_ARCH)

#$(call import-add-path, $(OR_LIB_PATH))

#LOCAL_PATH += $(OR_LIB_PATH)/$(TARGET_ARCH)
LOCAL_LDLIBS += -L$(OR_LIB_PATH)/$(TARGET_ARCH) -lpng -lz
LOCAL_SHARED_LIBRARIES += png
LOCAL_STATIC_LIBRARIES += boost_system_static boost_filesystem_static boost_program_options_static boost_regex_static z

include $(BUILD_SHARED_LIBRARY)

$(call import-module,boost/1.58.0)
5 changes: 5 additions & 0 deletions lib/interfaces/android/jni/Application.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#NDK_TOOLCHAIN_VERSION := 4.9
APP_STL := gnustl_shared
APP_CPPFLAGS += -std=gnu++11
APP_ABI := armeabi x86
APP_PLATFORM = android-14
177 changes: 177 additions & 0 deletions lib/interfaces/android/prepare.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#!/usr/bin/env ruby

require 'git'
require 'fileutils'

@build_dir = ARGV[0] || Dir.pwd

@build_api_level = 14
@build_targets = ["arm", "arm64", "x86", "x86_64"] #, "mips"]

puts "=== Preparing Android build dependencies"

def init()
if @build_api_level < 21
@build_targets = ["arm", "x86"] #, "mips"]
end

FileUtils.mkdir_p("#{@build_dir}") unless File.exists? "#{@build_dir}"
Dir.chdir(@build_dir)
@build_dir = Dir.pwd
end

def chain_env(arch)
case arch
when "arm"
return "CC=\"#{@build_dir}/toolchains/arm/bin/arm-linux-androideabi-gcc --sysroot=$CRYSTAX_NDK/platforms/android-#{@build_api_level}/arch-arm\" LD=#{@build_dir}/toolchains/arm/bin/arm-linux-androideabi-ld AR=#{@build_dir}/toolchains/arm/bin/arm-linux-androideabi-ar RANLIB=#{@build_dir}/toolchains/arm/bin/arm-linux-androideabi-ranlib STRIP=#{@build_dir}/toolchains/arm/bin/arm-linux-androideabi-strip "
when "x86"
return "CC=\"#{@build_dir}/toolchains/x86/bin/i686-linux-android-gcc --sysroot=$CRYSTAX_NDK/platforms/android-#{@build_api_level}/arch-x86\" LD=#{@build_dir}/toolchains/x86/bin/i686-linux-android-ld AR=#{@build_dir}/toolchains/x86/bin/i686-linux-android-ar RANLIB=#{@build_dir}/toolchains/x86/bin/i686-linux-android-ranlib STRIP=#{@build_dir}/toolchains/x86/bin/i686-linux-android-strip "
when "mips"
return "CC=\"#{@build_dir}/toolchains/mips/bin/mipsel-linux-android-gcc --sysroot=$CRYSTAX_NDK/platforms/android-#{@build_api_level}/arch-mips\" LD=#{@build_dir}/toolchains/mips/bin/mipsel-linux-android-ld AR=#{@build_dir}/toolchains/mips/bin/mipsel-linux-android-ar RANLIB=#{@build_dir}/toolchains/mips/bin/mipsel-linux-android-ranlib STRIP=#{@build_dir}/toolchains/mips/bin/mipsel-linux-android-strip "
when "arm64"
return "CC=\"#{@build_dir}/toolchains/arm64/bin/aarch64-linux-android-gcc --sysroot=$CRYSTAX_NDK/platforms/android-#{@build_api_level}/arch-arm64\" LD=#{@build_dir}/toolchains/arm64/bin/aarch64-linux-android-ld AR=#{@build_dir}/toolchains/arm64/bin/aarch64-linux-android-ar RANLIB=#{@build_dir}/toolchains/arm64/bin/aarch64-linux-android-ranlib STRIP=#{@build_dir}/toolchains/arm64/bin/aarch64-linux-android-strip "
when "x86_64"
return "CC=\"#{@build_dir}/toolchains/x86_64/bin/x86_64-linux-android-gcc --sysroot=$CRYSTAX_NDK/platforms/android-#{@build_api_level}/arch-x86_64\" LD=#{@build_dir}/toolchains/x86_64/bin/x86_64-linux-android-ld AR=#{@build_dir}/toolchains/x86_64/bin/x86_64-linux-android-ar RANLIB=#{@build_dir}/toolchains/x86_64/bin/x86_64-linux-android-ranlib STRIP=#{@build_dir}/toolchains/x86_64/bin/x86_64-linux-android-strip "
end
end

def setup_paths()
# base
Dir.mkdir("#{@build_dir}/natives") unless File.exists? "#{@build_dir}/natives"

# include
Dir.mkdir("#{@build_dir}/natives/include") unless File.exists? "#{@build_dir}/natives/include"
@build_targets.each do |target|
Dir.mkdir("#{@build_dir}/natives/include/#{target}") unless File.exists? "#{@build_dir}/natives/include/#{target}"
end

# lib
Dir.mkdir("#{@build_dir}/natives/lib") unless File.exists? "#{@build_dir}/natives/lib"
@build_targets.each do |target|
Dir.mkdir("#{@build_dir}/natives/lib/#{target}") unless File.exists? "#{@build_dir}/natives/lib/#{target}"
end

# bin
Dir.mkdir("#{@build_dir}/natives/bin") unless File.exists? "#{@build_dir}/natives/bin"
@build_targets.each do |target|
Dir.mkdir("#{@build_dir}/natives/bin/#{target}") unless File.exists? "#{@build_dir}/natives/bin/#{target}"
end

# jumper links
@build_targets.each do |target|
Dir.mkdir("#{@build_dir}/natives/#{target}") unless File.exists? "#{@build_dir}/natives/#{target}"
FileUtils.ln_s("#{@build_dir}/natives/bin/#{target}", "#{@build_dir}/natives/#{target}/bin") unless File.exists? "#{@build_dir}/natives/#{target}/bin"
FileUtils.ln_s("#{@build_dir}/natives/include/#{target}", "#{@build_dir}/natives/#{target}/include") unless File.exists? "#{@build_dir}/natives/#{target}/include"
FileUtils.ln_s("#{@build_dir}/natives/lib/#{target}", "#{@build_dir}/natives/#{target}/lib") unless File.exists? "#{@build_dir}/natives/#{target}/lib"
end
end

# Buld Chains
def prepare_chains()
puts "== Preparing Android NDK Build Chains"
@build_targets.each do |target|
puts "= #{target}..."
`$CRYSTAX_NDK/build/tools/make-standalone-toolchain.sh --platform=android-#{@build_api_level} --arch=#{target} --install-dir=#{@build_dir}/toolchains/#{target}` unless Dir.exists?("#{@build_dir}/toolchains/#{target}")
end

FileUtils.mkdir_p("#{@build_dir}/natives/lib")
FileUtils.mkdir_p("#{@build_dir}/natives/include")
FileUtils.mkdir_p("#{@build_dir}/natives")
@build_targets.each do |target|
FileUtils.mkdir_p("#{@build_dir}/natives/lib/#{target}")
end
end

# libpng
def build_libpng()
if Dir.exists? "#{@build_dir}/libpng"
puts "libpng repository found. Updating..."
Dir.chdir "#{@build_dir}/libpng"
`git reset HEAD --hard`
`git clean -fdx`
puts 'Updated.'
else
puts 'libpng repository not found. Cloning...'
Dir.chdir "#{@build_dir}"
`git clone https://github.com/glennrp/libpng`
puts 'Cloned.'
end

Dir.chdir "#{@build_dir}/libpng"
`git checkout v1.6.25`

puts '== Building libpng'

puts '= Building for arm'
`git clean -fdx`
`autoreconf --force --install`
`#{chain_env('arm')} ./configure --prefix=#{@build_dir}/natives/arm/ --disable-static --host=arm-linux-androideabi && make && make install`

puts '= Building for x86'
`git clean -fdx`
`autoreconf --force --install`
`#{chain_env('x86')} ./configure --prefix=#{@build_dir}/natives/x86/ --disable-static --host=i686-linux-android && make && make install`

if @build_targets.include? 'mips'
puts '= Building for mips'
`git clean -fdx`
`autoreconf --force --install`
`#{chain_env('mips')} ./configure --prefix=#{@build_dir}/natives/mips/ --disable-static --host=mipsel-linux-android && make && make install`
end

if @build_api_level > 20
if @build_targets.include? 'arm64'
puts '= Building for arm64'
`git clean -fdx`
`autoreconf --force --install`
`#{chain_env('arm64')} ./configure --prefix=#{@build_dir}/natives/arm64/ --disable-static --host=aarch64-linux-android && make && make install`
end

if @build_targets.include? 'x86_64'
puts '= Building for x86_64'
`git clean -fdx`
`autoreconf --force --install`
`#{chain_env('x86_64')} ./configure --prefix=#{@build_dir}/natives/x86_64/ --disable-static --host=x86_64-linux-android && make && make install`
end
end

Dir.chdir @build_dir
end

def check_lock()
if File.exists? "#{@build_dir}/buildlock"
puts '=> Build lock found. Skipping dependency preparation.'
puts '=> *Delete the buildlock file to update and regenerate.'
exit 0
end
end

def check_env()
if ENV['CRYSTAX_NDK'] != nil && ENV['CRYSTAX_NDK'] != ""
puts "CRYSTAX_NDK is set to: #{ENV['CRYSTAX_NDK']}"
else
puts "CRYSTAX_NDK is not set! You must set the CRYSTAX_NDK environment variable."
exit 1
end
end

def set_lock()
# Create lock and exit
puts "Dependencies acquired. Generating build lock."
lock_file = File.new("#{@build_dir}/buildlock", 'w')
lock_file.puts "Delete this file to re-build Android build dependencies"
lock_file.close
end

check_lock()

init()
check_env()
setup_paths()
prepare_chains()

build_libpng()

set_lock()

exit 0
Loading

0 comments on commit 8bed77a

Please sign in to comment.