Skip to content
This repository has been archived by the owner on Jul 4, 2018. It is now read-only.

Commit

Permalink
Functioning multi-project deps.
Browse files Browse the repository at this point in the history
- Users must call configureNativeBuild() at the end of their j2objcConfig.
- dependsOnJ2objcLib with a project will automatically wire up all dependencies to another j2objc project
- extra* flags allow you to customize the objective-c builds.
- remove lib/ prefix from all translateClassPaths

Ugly but it works.  The inability to reconfigure a previously
created native component is an issue others are hitting too:
https://discuss.gradle.org/t/problem-with-model-block-when-switching-from-2-2-1-to-2-4/9937

Fixes j2objc-contrib#153, Fixes j2objc-contrib#51
  • Loading branch information
advayDev1 committed Jun 12, 2015
1 parent c5b20c0 commit 85deaeb
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package com.github.j2objccontrib.j2objcgradle

import com.github.j2objccontrib.j2objcgradle.tasks.J2objcUtils
import groovy.transform.PackageScope
import org.gradle.api.Project
import org.gradle.nativeplatform.NativeExecutableSpec
import org.gradle.nativeplatform.NativeLibraryBinary
import org.gradle.nativeplatform.NativeLibrarySpec
import org.gradle.nativeplatform.toolchain.Clang

/**
*
*/
class J2objcNativeCompilation {
def apply(Project project, File srcGenDir) {

final Project project
J2objcNativeCompilation(Project project) {
this.project = project
}

@PackageScope
def apply(File srcGenDir) {
project.with {
// Wire up dependencies with tasks created dynamically by native plugin(s).
tasks.whenTaskAdded { task ->
Expand Down Expand Up @@ -156,6 +162,7 @@ class J2objcNativeCompilation {
objc {
source {
srcDirs "${srcGenDir}", "${buildDir}/j2objcHackToForceCompilation"
srcDirs j2objcConfig.extraObjcSrcDirs
include '**/*.m'
exclude '**/*Test.m'
}
Expand All @@ -174,6 +181,12 @@ class J2objcNativeCompilation {
targetPlatform 'ios_i386'
targetPlatform 'ios_x86_64'
targetPlatform 'x86_64'

binaries.all {
beforeProjects.each { beforeProject ->
lib project: beforeProject.path, library: "${beforeProject.name}-j2objc"
}
}
}

// Create an executable binary from a library containing just the test source code linked to
Expand All @@ -189,6 +202,9 @@ class J2objcNativeCompilation {
}
binaries.all {
lib library: "${project.name}-j2objc", linkage: 'static'
beforeProjects.each { beforeProject ->
lib project: beforeProject.path, library: "${beforeProject.name}-j2objc", linkage: 'static'
}

// J2ObjC provided libraries for testing only
linker.args '-ljunit'
Expand All @@ -214,6 +230,7 @@ class J2objcNativeCompilation {
objcCompiler.args "-I$j2objcPath/include"
objcCompiler.args '-Werror', '-Wno-parentheses', '-fno-strict-overflow'
objcCompiler.args '-std=c11'
objcCompiler.args j2objcConfig.extraObjcCompilerArgs

linker.args '-ObjC'

Expand All @@ -228,6 +245,7 @@ class J2objcNativeCompilation {
linker.args '-lz' // java.util.zip
linker.args '-framework', 'foundation' // core ObjC classes: NSObject, NSString
linker.args '-framework', 'Security' // secure hash generation
linker.args j2objcConfig.extraLinkerArgs

if (buildType == buildTypes.debug) {
objcCompiler.args "-g"
Expand All @@ -245,6 +263,12 @@ class J2objcNativeCompilation {
}
}
}

List<Project> beforeProjects = []
@PackageScope
def dependsOnJ2objcLib(Project beforeProject) {
beforeProjects.add(beforeProject)
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,16 @@ class J2objcPlugin implements Plugin<Project> {
throw new InvalidUserDataException(message)
}

extensions.create('j2objcConfig', J2objcPluginExtension)
extensions.create('j2objcConfig', J2objcPluginExtension, project)
afterEvaluate { evaluatedProject ->
// Validate minimally required parameters.
// j2objcHome() will throw the appropriate exception internally.
assert J2objcUtils.j2objcHome(evaluatedProject)
evaluatedProject.j2objcConfig.configureDefaults(evaluatedProject)

if (!evaluatedProject.j2objcConfig.isNativeBuildConfigured()) {
def message = "You must call configureNativeBuild() in j2objcConfig { }."
throw new InvalidUserDataException(message)
}
}

// This is an intermediate directory only. Clients should use only directories
Expand Down Expand Up @@ -130,9 +134,6 @@ class J2objcPlugin implements Plugin<Project> {
srcGenDir = j2objcSrcGenDir
}

// Configures native compilation for the production library and the test executable.
new J2objcNativeCompilation().apply(project, j2objcSrcGenDir)

// Note the 'debugTestJ2objcExecutable' task is dynamically created by the objective-c plugin applied
// on the above line. It is specified by the testJ2objc native component.
tasks.create(name: 'j2objcTest', type: J2objcTestTask,
Expand All @@ -142,10 +143,14 @@ class J2objcPlugin implements Plugin<Project> {
description 'Runs all tests in the generated Objective-C code'
testBinaryFile = file("${buildDir}/binaries/testJ2objcExecutable/debug/testJ2objc")
}



// 'check' task is added by 'java' plugin, it depends on 'test' and
// all the other verification tasks, now including 'j2objcTest'.
lateDependsOn(project, 'check', 'j2objcTest')


tasks.create(name: 'j2objcPackLibrariesDebug', type: J2objcPackLibrariesTask,
dependsOn: 'buildAllObjcLibraries') {
group 'build'
Expand Down Expand Up @@ -178,6 +183,10 @@ class J2objcPlugin implements Plugin<Project> {
description 'Depends on j2objc translation, create a Pod file link it to Xcode project'
srcGenDir = j2objcSrcGenDir
}


// Configures native compilation for the production library and the test executable.
// new J2objcNativeCompilation(project).apply(j2objcSrcGenDir)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,22 @@

package com.github.j2objccontrib.j2objcgradle

import groovy.transform.PackageScope
import org.gradle.api.InvalidUserDataException
import org.gradle.api.Project
import org.gradle.api.tasks.util.PatternSet
import org.gradle.util.ConfigureUtil

/**
* Further configuration uses the following fields, setting them in j2objcConfig within build.gradle
*/
class J2objcPluginExtension {

final protected Project extendedProject
J2objcPluginExtension(Project extendedProject) {
assert extendedProject != null
this.extendedProject = extendedProject
configureDefaults()
}

/**
* Where to assemble generated main source files.
* <p/>
Expand Down Expand Up @@ -163,6 +169,56 @@ class J2objcPluginExtension {
// TODO: Handle this automatically in the future.
boolean appendProjectDependenciesToSourcepath = false

/**
* @see #dependsOnJ2objcLib(org.gradle.api.Project)
*/
def dependsOnJ2objcLib(String beforeProjectName) {
return dependsOnJ2objcLib(extendedProject.project(beforeProjectName))
}

protected J2objcNativeCompilation nativeCompilation
/**
* Uses the generated headers and compiled j2objc libraries of the given project when
* compiling this project.
* <p/>
* Generally every cross-project 'compile' dependency should have a corresponding
* call to dependsOnJ2objcLib.
* <p/>
* It is safe to use this in conjunction with --build-closure, however do not duplicate
* this project's Java or Objective C source and/or libraries in any of the translation
* or compilation configuration flags; this method sets those up correctly to not
* re-compile beforeProject's source.
*/
// TODO: Do this automatically based on project dependencies.
def dependsOnJ2objcLib(Project beforeProject) {
// We need to have j2objcConfig on the beforeProject configured first.
extendedProject.evaluationDependsOn beforeProject.path

extendedProject.with {
if (!beforeProject.plugins.hasPlugin(J2objcPlugin)) {
def message = "$beforeProject does not use the j2objc plugin.\n" +
"dependsOnJ2objcLib can be used only with another project that\n" +
"itself uses the j2objc plugin."
throw new InvalidUserDataException(message)
}

// Build the java/objc libraries and the objc headers of
// the other project first.
j2objcPreBuild.dependsOn beforeProject.j2objcAssemble
// Since we assert the presence of the J2objcPlugin above,
// we are guaranteed that the java plugin, which creates the jar task,
// is also present.
j2objcPreBuild.dependsOn beforeProject.jar

logger.debug "$extendedProject:j2objcTranslate must use ${beforeProject.jar.archivePath}"
j2objcConfig {
translateClassPaths += beforeProject.jar.archivePath
}
}

nativeCompilation.dependsOnJ2objcLib(beforeProject)
}

// TEST
/**
* Flags copied verbatim to testrunner command.
Expand Down Expand Up @@ -210,7 +266,22 @@ class J2objcPluginExtension {
return ConfigureUtil.configure(cl, testPattern)
}

// LINK
// Native build customization.
/**
* Directories of objective-c source to compile in addition to the
* translated source.
*/
String[] extraObjcSrcDirs = []
/**
* Additional arguments to pass to the objective-c compiler.
*/
String[] extraObjcCompilerArgs = []
/**
* Additional arguments to pass to the native linker.
*/
String[] extraLinkerArgs = []

// XCODE
/**
* Directory of the target Xcode project.
*/
Expand All @@ -222,17 +293,28 @@ class J2objcPluginExtension {
String xcodeTarget = null

// Configures defaults whose values are dependent on the project.
@PackageScope
def configureDefaults(Project project) {
protected def configureDefaults() {
nativeCompilation = new J2objcNativeCompilation(extendedProject)
// Provide defaults for assembly output locations.
if (destSrcDir == null) {
destSrcDir = "${project.buildDir}/j2objcOutputs/src/main/objc"
}
if (destSrcDirTest == null) {
destSrcDirTest = "${project.buildDir}/j2objcOutputs/src/test/objc"
}
if (destLibDir == null) {
destLibDir = "${project.buildDir}/j2objcOutputs/lib"
}
destSrcDir = "${extendedProject.buildDir}/j2objcOutputs/src/main/objc"
destSrcDirTest = "${extendedProject.buildDir}/j2objcOutputs/src/test/objc"
destLibDir = "${extendedProject.buildDir}/j2objcOutputs/lib"
}

protected boolean nativeBuildConfigured = false
/**
* Configures the native build using. Must be called at the very
* end of your j2objcConfig block.
*/
// TODO: When Gradle makes it possible to modify a native build config
// after initial creation, we can remove this, and have methods on this object
// mutate the existing native model { } block. See:
// https://discuss.gradle.org/t/problem-with-model-block-when-switching-from-2-2-1-to-2-4/9937
def configureNativeBuild() {
nativeCompilation.apply(extendedProject.file("${extendedProject.buildDir}/j2objcSrcGen"))
nativeBuildConfigured = true
}
boolean isNativeBuildConfigured() {
return nativeBuildConfigured
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class J2objcCycleFinderTask extends DefaultTask {
allFiles = allFiles.plus(project.files(it))
}
translateClassPaths.each {
allFiles = allFiles.plus(project.files('lib/' + it))
allFiles = allFiles.plus(project.files(it))
}
return allFiles
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package com.github.j2objccontrib.j2objcgradle.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
Expand Down Expand Up @@ -64,15 +63,7 @@ class J2objcTranslateTask extends DefaultTask {
allFiles = allFiles.plus(project.files(it))
}
translateClassPaths.each {
allFiles = allFiles.plus(project.files('lib/' + it))
}
if (getAppendProjectDependenciesToSourcepath()) {
project.configurations.compile.allDependencies.each { dep ->
if (dep instanceof ProjectDependency) {
def depProj = ((ProjectDependency) dep).getDependencyProject()
allFiles = allFiles.plus(J2objcUtils.srcDirs(depProj, 'main', 'java'))
}
}
allFiles = allFiles.plus(project.files(it))
}
return allFiles
}
Expand All @@ -92,11 +83,6 @@ class J2objcTranslateTask extends DefaultTask {
@Input @Optional
String getTranslateSourcepaths() { return project.j2objcConfig.translateSourcepaths }

@Input
boolean getAppendProjectDependenciesToSourcepath() {
return project.j2objcConfig.appendProjectDependenciesToSourcepath
}

@Input
boolean getFilenameCollisionCheck() { return project.j2objcConfig.filenameCollisionCheck }

Expand Down Expand Up @@ -204,20 +190,6 @@ class J2objcTranslateTask extends DefaultTask {
// Generated Files
sourcepath += J2objcUtils.absolutePathOrEmpty(project, getGeneratedSourceDirs())

// Project Dependencies
if (getAppendProjectDependenciesToSourcepath()) {
def depSourcePaths = []
project.configurations.compile.allDependencies.each { dep ->
if (dep instanceof ProjectDependency) {
def depProj = ((ProjectDependency) dep).getDependencyProject()
J2objcUtils.srcDirs(depProj, 'main', 'java').srcDirs.each {
depSourcePaths.add(it.path)
}
}
}
sourcepath += ':' + depSourcePaths.join(':')
}

// TODO perform file collision check with already translated files in the srcGenDir
if (getFilenameCollisionCheck()) {
J2objcUtils.filenameCollisionCheck(srcFiles)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,7 @@ class J2objcUtils {
def classPathList = []
// user defined libraries
libraries.each { library ->
def libPath = "${proj.projectDir}/lib/" + library
classPathList += libPath
classPathList += proj.file(library).absolutePath
}
// j2objc default libraries
translateJ2objcLibs.each { library ->
Expand Down

0 comments on commit 85deaeb

Please sign in to comment.