Skip to content

Instantly share code, notes, and snippets.

@freekh
Created September 16, 2014 15:08
Show Gist options
  • Save freekh/a3b0aa703060decce156 to your computer and use it in GitHub Desktop.
Save freekh/a3b0aa703060decce156 to your computer and use it in GitHub Desktop.
Platforms model

Platform variance: The concept of variance is one of the key features on our roadmap (http://www.gradle.org/roadmap#variant). The highlevel goal is to find a flexible and safe way for users to describe what they want their build to do. From this we can infer what needs to be done to get there.

There are a bunch of considerations to take:

  • we need an easy way to define new platforms. Examples: Scala, Android, Play, ....
  • we need to specialize platforms: Scala is a Jvm platform with some additional properties, Android is a combination of Jvm and C (NDK) and some additional properties, Gradle is just Groovy with some extra APIs, ...
  • we need an easy way to verify determine whether a platform can be created.

Below are some alternative strategies. I am leaning towards Alt 1, but I am still trying to piece together how things work in general.

Alternative 1: a platform defines what a library is In this alternative platforms becomes a high-level concept (like BinarySpecs, ComponentSpecs, LibrarySpecs), which plugins define.

Model overview:

  • There is a PlatformPlugin which registers a PlatformContainer.
  • Language plugins (or others) defines a set of valid platforms to the PlatformContainer.
  • A specific PlatformVariant is a composite of multiple platforms.
  • For each platform variant, binary spec and library spec combination a compile task created. This can be implemented through rules on the PlatformContainer (I think).
  • Validation happens through ToolChains (which knows what we can build): for each language defined we find the toolchains needed (for scala we need a scala toolchain and a java toolchain) then select the corresponding platform variance (for the java toolchain we might select targetCompatibility 1.7, for the scala toolchain binaryVersion 2.10 and version 2.10.4). If there is an error or no toolchains can be found we mark the binary as non-buildable and print out a report.

Pros:

  • Free to mix multiple platforms together Cons:
  • No type level validation on what works together.
  • Unclear whether it is possible to do this.
  • Possibly hard to define exactly which platforms works together (less stable)?

Example (again, only to give a better sense) snippets:

//PlatformPlugin.java

@RuleSource
static class Rules {
    @Model
    PlatformContainer platforms(ServiceRegistry serviceRegistry) {
       Instantiator instantiator = serviceRegistry.get(Instantiator.class);
       return instantiator.newInstance(DefaultPlatformContainer.class, instantiator);
    }
    
    @Mutate
    void createBinaries(BinaryContainer binarySpecs, PlatformContainer platforms, ...) { 
      //find toolChains that matches platforms and create binaries based on this and component specs
    }
}

//ScalaLanguagePlugin.java

@RuleSource
static class Rules {
   @Mutate
   public void createScalaPlatform(PlatformContainer platforms) {
      
   }
   
   @Mutate
   public void createScalaToolChains(ToolChainRegistryInternal toolChains) {
     //...
   }
}

//ScalaToolChain.java
public Set<Platform> select(Set<Platform> platforms) {
    //
}

Example dsl (please ignore syntax here - the important thing is the model. Example only provided as a reference to better explain.):

    apply plugin: 'scala-lang'
    apply plugin: 'android'

    libraries {
        myLib
    }
    
   platforms {
        myLib { //or myLib then platforms does not matter
          [ variant {
              jvm {
                targetCompatibility "1.7"
              }
              scala {
                  binaryVersion "2.10"
                  version "2.10.4"
              }
              android {
                  compileSdkVersion 19
                  ndkRevision "10b"
              }
            }, variant {
              scala {
                  binaryVersion "2.11"
                  version "2.11.2"
              }
              android {
                  compileSdkVersion 19
                  ndkRevision "10b"
              } //if I tried to have rust {} here Gradle should tell me that there is no toolChain that can build scala, android and rust
            }]
        }
    }

Alternative 2: a language defines a platform which can be spesialized Each language plugin sets up its own rules that extracts. Platforms are only connected through inheritence.

Model architecture overview:

  • TODO

Pros:

  • Static checking
  • Easier to define what works together. Cons:
  • Hard to come up with a flexible approach.

Example dsl (ignore syntax - the important thing is the model):

    apply plugin: 'scala-lang'
    apply plugin: 'android'

    jvm {
      libraries {
        myLib {
          scala {
            binaryVersion "2.10"
            version "2.10.4"
          }
          android {
            compileSdkVersion 19
            ndkRevision "10b"
          }
        }
      }
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment