-
-
Save CAMOBAP/ed9aa6a7549787b5eea4b2048b896747 to your computer and use it in GitHub Desktop.
include(default) | |
standalone_toolchain=/opt/android-ndk-toolchains/arm-27 | |
ndk_home=/opt/android-ndk | |
api_level=27 | |
target_host=arm-linux-androideabi | |
cc_compiler=clang | |
cxx_compiler=clang++ | |
target_specific_flags=-mfpu=neon | |
[settings] | |
os=Android | |
os.api_level=$api_level | |
arch=armv7hf | |
compiler=clang | |
compiler.version=7.0 | |
compiler.libcxx=libstdc++ | |
[env] | |
ANDROID_NDK_HOME=$ndk_home | |
CONAN_CMAKE_FIND_ROOT_PATH=$standalone_toolchain/sysroot | |
PATH=[$standalone_toolchain/bin] | |
CHOST=$target_host | |
AR=$target_host-ar | |
AS=$target_host-as | |
RANLIB=$target_host-ranlib | |
CC=$target_host-$cc_compiler | |
CXX=$target_host-$cxx_compiler | |
LD=$target_host-ld | |
STRIP=$target_host-strip | |
CFLAGS= -fPIE -fPIC -I$standalone_toolchain/include/c++/4.9.x -D__ANDROID__ -D__ANDROID_API__=$api_level $target_specific_flags | |
CXXFLAGS= -fPIE -fPIC -I$standalone_toolchain/include/c++/4.9.x -D__ANDROID__ -D__ANDROID_API__=$api_level $target_specific_flags | |
LDFLAGS= -pie -march=armv7-a -Wl,--fix-cortex-a8 |
standalone_toolchain=/opt/android-ndk-toolchains/x86_64-27 | |
ndk_home=/opt/android-ndk | |
api_level=27 | |
target_host=x86_64-linux-android | |
cc_compiler=clang | |
cxx_compiler=clang++ | |
target_specific_flags=-mfpu=neon | |
[settings] | |
os=Android | |
os.api_level=$api_level | |
arch=x86_64 | |
compiler=clang | |
compiler.version=7.0 | |
compiler.libcxx=libstdc++ | |
[env] | |
ANDROID_NDK_HOME=$ndk_home | |
CONAN_CMAKE_FIND_ROOT_PATH=$standalone_toolchain/sysroot | |
PATH=[$standalone_toolchain/bin] | |
CHOST=$target_host | |
AR=$target_host-ar | |
AS=$target_host-as | |
RANLIB=$target_host-ranlib | |
CC=$target_host-$cc_compiler | |
CXX=$target_host-$cxx_compiler | |
LD=$target_host-ld | |
STRIP=$target_host-strip | |
CFLAGS= -fPIE -fPIC -I$standalone_toolchain/include/c++/4.9.x -D__ANDROID__ -D__ANDROID_API__=$api_level $target_specific_flags | |
CXXFLAGS= -fPIE -fPIC -I$standalone_toolchain/include/c++/4.9.x -D__ANDROID__ -D__ANDROID_API__=$api_level $target_specific_flags | |
LDFLAGS= -pie |
apply plugin: 'com.android.application' | |
apply from: "${rootDir}/conan.gradle" | |
conan { | |
conanfile = 'src/main/cpp/conanfile.txt' | |
profile = 'android-${abi}' | |
} | |
android { | |
compileSdkVersion 28 | |
defaultConfig { | |
applicationId "org.camobap.conan.gradle.example" | |
minSdkVersion 27 | |
targetSdkVersion 28 | |
versionCode 1 | |
versionName "1.0" | |
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" | |
externalNativeBuild { | |
cmake { | |
abiFilters "armeabi-v7a", "x86_64" | |
arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_STL=c++_shared", | |
} | |
} | |
} | |
buildTypes { | |
release { | |
minifyEnabled true | |
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | |
} | |
} | |
externalNativeBuild { | |
cmake { | |
path "src/main/cpp/CMakeLists.txt" | |
} | |
} | |
} | |
clean.doLast { | |
delete file('.externalNativeBuild') | |
} | |
dependencies { | |
implementation 'com.android.support:appcompat-v7:28.0.0' | |
implementation 'com.android.support:support-annotations:28.0.0' | |
testImplementation 'junit:junit:4.12' | |
androidTestImplementation 'androidx.test:core:1.1.0' | |
androidTestImplementation 'androidx.test.ext:junit:1.1.0' | |
androidTestImplementation 'androidx.test:runner:1.1.1' | |
androidTestImplementation 'androidx.test:rules:1.1.1' | |
} |
import java.nio.file.Paths | |
import groovy.text.SimpleTemplateEngine | |
class ConanPluginExtension { | |
String conanfile = "src/main/cpp/conanfile.txt" | |
String profile = 'android-${abi}' // TODO maybe support map abi->filename | |
String outputDirPath = '${projectDir}/.externalNativeBuild/conan/${flavor}/${abi}' | |
} | |
class ConanPlugin implements Plugin<Project> { | |
def android | |
def extension | |
def conanfilePath | |
def conanProfileFileNameTemplate | |
def conanOutputDirPathTemplate | |
void validate(Project project) { | |
android = project.extensions.android | |
assert android: "Cannot be applied for non android projects" | |
conanfilePath = Paths.get(project.projectDir.absolutePath, extension.conanfile).toString() | |
assert project.file(conanfilePath).exists(): "conan file ${conanfilePath} doesn't exists" | |
conanProfileFileNameTemplate = extension.profile | |
conanOutputDirPathTemplate = extension.outputDirPath | |
} | |
void createTasksForAndroidExternalNativeBuild(Project project) { | |
android.applicationVariants.all { variant -> | |
def engine = new SimpleTemplateEngine() | |
for (def abi in android.defaultConfig.externalNativeBuild.cmake.abiFilters) { | |
def flavor = variant.name | |
def taskSuffix = "${abi.capitalize()}${flavor.capitalize()}" | |
def buildType = flavor.toLowerCase().contains('release') ? 'release' : 'debug' | |
def params = ['abi': abi, 'flavor': flavor, 'projectDir': project.projectDir, 'buildType': buildType] | |
def conanProfileFileName = engine.createTemplate(conanProfileFileNameTemplate).make(params).toString() | |
def conanOutputDirPath = engine.createTemplate(conanOutputDirPathTemplate).make(params).toString() | |
def conanInstallTaskName = "conanInstall${taskSuffix}" | |
def conanInstallTask = project.task(conanInstallTaskName, type: Exec) { | |
group 'Conan tasks' | |
description 'Run conan to get and build missing dependencies' | |
workingDir conanOutputDirPath | |
commandLine 'conan', 'install', conanfilePath, | |
'--profile', conanProfileFileName, | |
'--settings', "build_type=${buildType.capitalize()}", | |
'--install-folder', workingDir, | |
'--build', 'missing' | |
inputs.files conanfilePath | |
outputs.dir workingDir | |
doFirst { | |
workingDir.mkdirs() | |
} | |
} | |
def conanCheckProfileTaskName = "conanCheckProfileFor${taskSuffix}" | |
project.task(conanCheckProfileTaskName) { | |
group 'Conan tasks' | |
description 'Check that conan profile file exists' | |
doFirst { | |
if (!project.file(conanProfileFileName).exists()) { | |
def conanProfilePath = "${System.properties['user.home']}/.conan/profiles/${conanProfileFileName}" | |
assert project.file(conanProfilePath).exists() \ | |
: "Conan profile file \"${conanProfilePath}\" missing please check README.md" | |
} | |
} | |
} | |
def conanCleanTaskName = "conanClean${taskSuffix}" | |
project.task(conanCleanTaskName, type: Delete) { | |
group 'Conan tasks' | |
description 'Delete conan generated files' | |
delete conanOutputDirPath | |
} | |
conanInstallTask.dependsOn(conanCheckProfileTaskName) | |
project.tasks.findByName("externalNativeBuild${flavor.capitalize()}").dependsOn(conanInstallTaskName) | |
project.tasks.findByName("externalNativeBuildClean${flavor.capitalize()}").dependsOn(conanCleanTaskName) | |
} | |
} | |
} | |
void apply(Project project) { | |
extension = project.extensions.create('conan', ConanPluginExtension) | |
project.afterEvaluate { | |
validate(project) | |
createTasksForAndroidExternalNativeBuild(project) | |
} | |
} | |
} | |
apply plugin: ConanPlugin |
@ppetraki, my bad there were flavors in build.gradle
, please remove them (I have updated build.gradle
in this gist)
please run ./gradlew clean build
and show the error (you should not rely on sast
or regular
anymore in paths)
To support x86 please list it in https://gist.github.com/CAMOBAP795/ed9aa6a7549787b5eea4b2048b896747#file-build-gradle-L22
@CAMOBAP795
Thanks.
To build the fat APK you need to add this:
// https://stackoverflow.com/questions/36414219/install-failed-no-matching-abis-failed-to-extract-native-libraries-res-113
splits {
abi {
enable true
reset()
include 'x86', 'armeabi-v7a', 'x86_64'
// include defaultConfig.externalNativeBuild.getCmake().getAbiFilters().
universalApk true
}
}
I tried to reuse the abiFilters array (list) but there's a type error. I just don't know enough Java/Groovy yet to write anything more than shell like code atm :)
If flavors don't matter for the NDK build. Then lets dump it's metadata from the conan install path and use the actual build type in the format Cmake expects. Then we can do a direct include like this:.
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../conan_build/${CMAKE_BUILD_TYPE}/${ANDROID_ABI}/conanbuildinfo.cmake)
All that has to change in the plugin is:
diff --git a/conan.gradle b/conan.gradle
index e5a2c88..0857349 100644
--- a/conan.gradle
+++ b/conan.gradle
@@ -9,7 +9,7 @@ import groovy.text.SimpleTemplateEngine
class ConanPluginExtension {
String conanfile = "src/main/cpp/conanfile.txt"
String profile = 'android-${abi}' // TODO maybe support map abi->filename
- String outputDirPath = '${projectDir}/conan_build/${flavor}/${abi}'
+ String outputDirPath = '${projectDir}/conan_build/${buildType}/${abi}'
}
Where buildType is defined in the params map as follows
def params = ['abi': abi, 'flavor': flavor, 'projectDir': project.projectDir, 'buildType': buildType.capitalize()]
Now the conan_build tree looks like this:
ppetraki@vanguard:~/Sandbox/Games/conansdl2$ !tree
tree app/conan_build/
app/conan_build/
├── Debug
│ ├── armeabi-v7a
│ │ ├── conanbuildinfo.cmake
│ │ ├── conanbuildinfo.txt
│ │ ├── conaninfo.txt
│ │ ├── conan.lock
│ │ └── graph_info.json
│ ├── x86
│ │ ├── conanbuildinfo.cmake
│ │ ├── conanbuildinfo.txt
│ │ ├── conaninfo.txt
│ │ ├── conan.lock
│ │ └── graph_info.json
│ └── x86_64
│ ├── conanbuildinfo.cmake
│ ├── conanbuildinfo.txt
│ ├── conaninfo.txt
│ ├── conan.lock
│ └── graph_info.json
└── Release
├── armeabi-v7a
│ ├── conanbuildinfo.cmake
│ ├── conanbuildinfo.txt
│ ├── conaninfo.txt
│ ├── conan.lock
│ └── graph_info.json
├── x86
│ ├── conanbuildinfo.cmake
│ ├── conanbuildinfo.txt
│ ├── conaninfo.txt
│ ├── conan.lock
│ └── graph_info.json
└── x86_64
├── conanbuildinfo.cmake
├── conanbuildinfo.txt
├── conaninfo.txt
├── conan.lock
└── graph_info.json
8 directories, 30 files
@CAMOBAP795
I solved the "distclean" problem. It was a matter of different tasks being invoked by the IDE vs the CLI. I've created my own gist now as the plugin has diverged quite a bit from your original version. Feel free to merge the changes.
https://gist.github.com/ppetraki/ca8630cc272edcd6a881ed82aa30b559
I think this can be done with even less external config. Especially if you use the cmake_wrapper. As all of my profiles vary by just a single config string that could easily be driven to the conan CLI. Then the plugin could provide it's own default NDK profile and decorate it. Making it completely self contained.
Hi @ppetraki
Sorry for log silence
To build the fat APK you need to add this: ...
This not true, android building FAT APK out of the box, moreover split
section used to build separate APK for each ABI, according to official doe https://developer.android.com/studio/build/configure-apk-splits:
universalApk
If true, Gradle generates a universal APK in addition to per-ABI APKs. A universal APK contains code and resources for all ABIs in a single APK. The default value is false. Note that this option is only available in the splits.abi block. When building multiple APKs based on screen density, Gradle always generates a universal APK that contains code and resources for all screen densities.
If flavors don't matter for the NDK build....
Flavors have no relationships with NDK, most close equivalent in CMake
-word is a target
All that has to change in the plugin is ...
You can achieve the same by modifying the 'user' side only, no need to touch plugin for this
conan {
conanfile = 'src/main/cpp/conanfile.txt'
profile = 'android-${abi}'
outputDirPath = '${projectDir}/conan_build/${buildType}/${abi}'
}
So according what I found from your comment there is no reason to modify the plugin by itself,
@ppetraki correct me if I'm wrong
Would it be possible to release this as proper Gradle Plugin?
@janseeger probably not (at least in near future)
@CAMOBAP795
Turns out I really needed to target x86 instead of x86_64 and configure gradle to build a universal apk. It's working now. I've fixed some of the clean target issues by added a dependency on "externalNativeBuildCleanRegularDebug". The other weird thing I'm seeing is it doesn't always regenerate the conan install targets. Sometimes it will drop release, sometimes it adds sastRelease and sastDebug. It's odd.
While my if else hack works. What would be ideal is if the plugin generated a top level buildinfo,cmake file in conan_build/ (or whatever) that accounted for all the build types generated by gradle and how they map to cmake build types. Then we can just include a single path and it will "just work".
That would be sick (⌐■_■)