/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.build.gradle.ndk.internal; import static com.android.build.gradle.ndk.internal.BinaryToolHelper.getCCompiler; import static com.android.build.gradle.ndk.internal.BinaryToolHelper.getCppCompiler; import com.android.annotations.NonNull; import com.android.build.gradle.internal.NdkHandler; import com.android.build.gradle.internal.core.Abi; import com.android.build.gradle.managed.NdkConfig; import com.android.build.gradle.model.AndroidComponentModelSourceSet; import com.android.build.gradle.tasks.GdbSetupTask; import com.android.build.gradle.tasks.StripDebugSymbolTask; import com.android.utils.StringHelper; import com.google.common.base.Objects; import org.gradle.api.Action; import org.gradle.api.PolymorphicDomainObjectContainer; import org.gradle.api.Task; import org.gradle.api.tasks.Copy; import org.gradle.language.base.FunctionalSourceSet; import org.gradle.language.base.LanguageSourceSet; import org.gradle.language.c.CSourceSet; import org.gradle.language.c.tasks.CCompile; import org.gradle.language.cpp.CppSourceSet; import org.gradle.language.cpp.tasks.CppCompile; import org.gradle.model.ModelMap; import org.gradle.nativeplatform.NativeBinarySpec; import org.gradle.nativeplatform.NativeLibrarySpec; import org.gradle.nativeplatform.SharedLibraryBinarySpec; import org.gradle.platform.base.BinarySpec; import java.io.File; /** * Configure settings used by the native binaries. */ public class NdkConfiguration { public static void configureProperties( NativeLibrarySpec library, final AndroidComponentModelSourceSet sources, final File buildDir, final NdkHandler ndkHandler) { for (Abi abi : ndkHandler.getSupportedAbis()) { library.targetPlatform(abi.getName()); } library.getBinaries() .withType(SharedLibraryBinarySpec.class, new Action<SharedLibraryBinarySpec>() { @Override public void execute(final SharedLibraryBinarySpec binary) { sourceIfExist(binary, sources, "main"); sourceIfExist(binary, sources, binary.getFlavor().getName()); sourceIfExist(binary, sources, binary.getBuildType().getName()); sourceIfExist(binary, sources, binary.getFlavor().getName() + StringHelper.capitalize(binary.getBuildType().getName())); getCCompiler(binary).define("ANDROID"); getCppCompiler(binary).define("ANDROID"); getCCompiler(binary).define("ANDROID_NDK"); getCppCompiler(binary).define("ANDROID_NDK"); // Replace output directory of compile tasks. binary.getTasks().withType(CCompile.class, new Action<CCompile>() { @Override public void execute(CCompile task) { String sourceSetName = task.getObjectFileDir().getName(); task.setObjectFileDir( NdkNamingScheme.getObjectFilesOutputDirectory( binary, buildDir, sourceSetName)); } }); binary.getTasks().withType(CppCompile.class, new Action<CppCompile>() { @Override public void execute(CppCompile task) { String sourceSetName = task.getObjectFileDir().getName(); task.setObjectFileDir( NdkNamingScheme.getObjectFilesOutputDirectory( binary, buildDir, sourceSetName)); } }); new DefaultNativeToolSpecification().apply(binary); String sysroot = ndkHandler.getSysroot( Abi.getByName(binary.getTargetPlatform().getName())); getCCompiler(binary).args("--sysroot=" + sysroot); getCppCompiler(binary).args("--sysroot=" + sysroot); binary.getLinker().args("--sysroot=" + sysroot); binary.getLinker().args("-Wl,--build-id"); } }); } /** * Configure native binary with variant specific options. */ public static void configureBinary( SharedLibraryBinarySpec binary, final File buildDir, final NdkConfig ndkConfig, final NdkHandler ndkHandler) { // Set output library filename. binary.setSharedLibraryFile( new File( buildDir, NdkNamingScheme.getDebugLibraryDirectoryName(binary) + "/" + NdkNamingScheme.getSharedLibraryFileName( ndkConfig.getModuleName()))); String sysroot = ndkHandler.getSysroot( Abi.getByName(binary.getTargetPlatform().getName())); if (ndkConfig.getRenderscriptNdkMode()) { getCCompiler(binary).args("-I" + sysroot + "/usr/include/rs"); getCCompiler(binary).args("-I" + sysroot + "/usr/include/rs/cpp"); getCppCompiler(binary).args("-I" + sysroot + "/usr/include/rs"); getCppCompiler(binary).args("-I" + sysroot + "/usr/include/rs/cpp"); binary.getLinker().args("-L" + sysroot + "/usr/lib/rs"); } // STL flags must be applied before user defined flags to resolve possible undefined symbols // in the STL library. StlNativeToolSpecification stlConfig = new StlNativeToolSpecification( ndkHandler, ndkConfig.getStl(), binary.getTargetPlatform()); stlConfig.apply(binary); NativeToolSpecificationFactory.create( ndkHandler, binary.getTargetPlatform(), Objects.firstNonNull(ndkConfig.getDebuggable(), false)).apply( binary); // Add flags defined in NdkConfig for (String flag : ndkConfig.getCFlags()) { getCCompiler(binary).args(flag.trim()); } for (String flag : ndkConfig.getCppFlags()) { getCppCompiler(binary).args(flag.trim()); } for (String flag : ndkConfig.getLdFlags()) { binary.getLinker().args(flag.trim()); } for (String ldLib : ndkConfig.getLdLibs()) { binary.getLinker().args("-l" + ldLib.trim()); } } public static void createTasks( @NonNull ModelMap<Task> tasks, @NonNull SharedLibraryBinarySpec binary, @NonNull File buildDir, @NonNull NdkConfig ndkConfig, @NonNull NdkHandler ndkHandler) { String compileNdkTaskName = NdkNamingScheme.getNdkBuildTaskName(binary); tasks.create(compileNdkTaskName); StlConfiguration.createStlCopyTask(tasks, binary, buildDir, ndkHandler, ndkConfig.getStl(), compileNdkTaskName); if (Boolean.TRUE.equals(ndkConfig.getDebuggable())) { // TODO: Use AndroidTaskRegistry and scopes to create tasks in experimental plugin. setupNdkGdbDebug(tasks, binary, buildDir, ndkConfig, ndkHandler, compileNdkTaskName); } createStripDebugTask(tasks, binary, buildDir, ndkHandler, compileNdkTaskName); } /** * Add the sourceSet with the specified name to the binary if such sourceSet is defined. */ private static void sourceIfExist( BinarySpec binary, AndroidComponentModelSourceSet projectSourceSet, final String sourceSetName) { FunctionalSourceSet sourceSet = projectSourceSet.findByName(sourceSetName); if (sourceSet != null) { final LanguageSourceSet jni = sourceSet.getByName("jni"); binary.sources(new Action<PolymorphicDomainObjectContainer<LanguageSourceSet>>() { @Override public void execute( PolymorphicDomainObjectContainer<LanguageSourceSet> languageSourceSets) { // Hardcode the acceptable extension until we find a suitable DSL for user to // modify. languageSourceSets.create( sourceSetName + "C", CSourceSet.class, new Action<LanguageSourceSet>() { @Override public void execute(LanguageSourceSet source) { source.getSource().setSrcDirs(jni.getSource().getSrcDirs()); source.getSource().include("**/*.c"); source.getSource().exclude(jni.getSource().getExcludes()); } }); languageSourceSets.create( sourceSetName + "Cpp", CppSourceSet.class, new Action<LanguageSourceSet>() { @Override public void execute(LanguageSourceSet source) { source.getSource().setSrcDirs(jni.getSource().getSrcDirs()); source.getSource().include("**/*.C"); source.getSource().include("**/*.CPP"); source.getSource().include("**/*.c++"); source.getSource().include("**/*.cc"); source.getSource().include("**/*.cp"); source.getSource().include("**/*.cpp"); source.getSource().include("**/*.cxx"); source.getSource().exclude(jni.getSource().getExcludes()); } }); } }); } } /** * Setup tasks to create gdb.setup and copy gdbserver for NDK debugging. */ private static void setupNdkGdbDebug( @NonNull ModelMap<Task> tasks, @NonNull final NativeBinarySpec binary, @NonNull final File buildDir, @NonNull final NdkConfig ndkConfig, @NonNull final NdkHandler handler, @NonNull String buildTaskName) { final String copyGdbServerTaskName = NdkNamingScheme.getTaskName(binary, "copy", "GdbServer"); tasks.create(copyGdbServerTaskName, Copy.class, new Action<Copy>() { @Override public void execute(Copy task) { task.from(new File(handler.getPrebuiltDirectory( Abi.getByName(binary.getTargetPlatform().getName())), "gdbserver/gdbserver")); task.into(new File(buildDir, NdkNamingScheme.getOutputDirectoryName(binary))); } }); final String createGdbSetupTaskName = NdkNamingScheme.getTaskName(binary, "create", "Gdbsetup"); tasks.create(createGdbSetupTaskName, GdbSetupTask.class, new Action<GdbSetupTask>() { @Override public void execute(GdbSetupTask task) { task.setNdkHandler(handler); task.setExtension(ndkConfig); task.setBinary(binary); task.setOutputDir( new File(buildDir, NdkNamingScheme.getOutputDirectoryName(binary))); } }); tasks.named(buildTaskName, new Action<Task>() { @Override public void execute(Task task) { task.dependsOn(copyGdbServerTaskName); task.dependsOn(createGdbSetupTaskName); } }); } private static void createStripDebugTask( ModelMap<Task> tasks, final SharedLibraryBinarySpec binary, final File buildDir, final NdkHandler handler, String buildTaskName) { final String taskName = NdkNamingScheme.getTaskName(binary, "stripSymbols"); tasks.create( taskName, StripDebugSymbolTask.class, new StripDebugSymbolTask.ConfigAction(binary, buildDir, handler)); tasks.named(buildTaskName, new Action<Task>() { @Override public void execute(Task task) { task.dependsOn(taskName); } }); } }