使用sbt編譯Spark子項目


前言

最近為了解決Spark2.1的Bug,對Spark的源碼做了不少修改,需要對修改的代碼做編譯測試,如果編譯整個Spark項目快的話,也得半小時左右,所以基本上是改了哪個子項目就單獨對那個項目編譯打包。

Spark官方已經給出了如何使用mvn單獨編譯子項目的方法:http://spark.apache.org/docs/latest/building-spark.html#building-submodules-individually

使用mvn單獨編譯子項目是節約了不少時間。但是頻繁的改動項目,每次用mvn編譯還是挺耗時間的。

之前看官方文檔提到,對於開發者,為了提高效率,推薦使用sbt編譯。於是,又查了下文檔資料:http://spark.apache.org/developer-tools.html

咦,看到:Running Build Targets For Individual Projects,內容如下:

$ # sbt
$ build/sbt package
$ # Maven
$ build/mvn package -DskipTests -pl assembly

這不是坑么,雖然沒怎么用sbt編譯過Spark,但是sbt俺還是用過的。build/sbt package明明是編譯整個項目的好吧,這哪是編譯子項目啊。

翻遍官方所有跟編譯有關的資料,無果。

最后,研究了下Spark的sbt定義,也就是下project/SparkBuild.scala文件,找到了使用sbt編譯子項目的方法。

使用sbt編譯子項目

下面是對spark-core重新編譯打包的方法,我們需要使用REPL模式,大致的流程如下:

➜  spark git:(branch-2.1.0) ✗ ./build/sbt -Pyarn -Phadoop-2.6 -Phive              
...
[info] Set current project to spark-parent (in build file:/Users/stan/Projects/spark/)
> project core
[info] Set current project to spark-core (in build file:/Users/stan/Projects/spark/)
> package
[info] Updating {file:/Users/stan/Projects/spark/}tags...
[info] Resolving jline#jline;2.12.1 ...
...
[info] Packaging /Users/stan/Projects/spark/core/target/scala-2.11/spark-core_2.11-2.1.0.jar ...
[info] Done packaging.
[success] Total time: 213 s, completed 2017-2-15 16:58:15

最后將spark-core_2.11-2.1.0.jar替換到jars或者assembly/target/scala-2.11/jars目錄下就可以了。

選擇的子項目的關鍵是project命令,如何知道有哪些定義好的子項目呢?這個還得參考project/SparkBuild.scala中BuildCommons的定義:

object BuildCommons {

  private val buildLocation = file(".").getAbsoluteFile.getParentFile

  val sqlProjects@Seq(catalyst, sql, hive, hiveThriftServer, sqlKafka010) = Seq(
    "catalyst", "sql", "hive", "hive-thriftserver", "sql-kafka-0-10"
  ).map(ProjectRef(buildLocation, _))

  val streamingProjects@Seq(
    streaming, streamingFlumeSink, streamingFlume, streamingKafka, streamingKafka010
  ) = Seq(
    "streaming", "streaming-flume-sink", "streaming-flume", "streaming-kafka-0-8", "streaming-kafka-0-10"
  ).map(ProjectRef(buildLocation, _))

  val allProjects@Seq(
    core, graphx, mllib, mllibLocal, repl, networkCommon, networkShuffle, launcher, unsafe, tags, sketch, _*
  ) = Seq(
    "core", "graphx", "mllib", "mllib-local", "repl", "network-common", "network-shuffle", "launcher", "unsafe",
    "tags", "sketch"
  ).map(ProjectRef(buildLocation, _)) ++ sqlProjects ++ streamingProjects

  val optionallyEnabledProjects@Seq(mesos, yarn, java8Tests, sparkGangliaLgpl,
    streamingKinesisAsl, dockerIntegrationTests) =
    Seq("mesos", "yarn", "java8-tests", "ganglia-lgpl", "streaming-kinesis-asl",
      "docker-integration-tests").map(ProjectRef(buildLocation, _))

  val assemblyProjects@Seq(networkYarn, streamingFlumeAssembly, streamingKafkaAssembly, streamingKafka010Assembly, streamingKinesisAslAssembly) =
    Seq("network-yarn", "streaming-flume-assembly", "streaming-kafka-0-8-assembly", "streaming-kafka-0-10-assembly", "streaming-kinesis-asl-assembly")
      .map(ProjectRef(buildLocation, _))

  val copyJarsProjects@Seq(assembly, examples) = Seq("assembly", "examples")
    .map(ProjectRef(buildLocation, _))

  val tools = ProjectRef(buildLocation, "tools")
  // Root project.
  val spark = ProjectRef(buildLocation, "spark")
  val sparkHome = buildLocation

  val testTempDir = s"$sparkHome/target/tmp"

  val javacJVMVersion = settingKey[String]("source and target JVM version for javac")
  val scalacJVMVersion = settingKey[String]("source and target JVM version for scalac")
}

我們看下這個例子:

  val sqlProjects@Seq(catalyst, sql, hive, hiveThriftServer, sqlKafka010) = Seq(
    "catalyst", "sql", "hive", "hive-thriftserver", "sql-kafka-0-10"
  ).map(ProjectRef(buildLocation, _))

這是對sql項目定義的子項目,有:catalyst, sql, hive, hive-thriftserver, sql-kafka-0-10

我們如果需要編譯catalyst這個項目,只需要進入sbt:project catalyst選擇catalyst項目就可以了,后面使用的compile、package等命令都是針對這個項目的。

多謝知乎@鳳凰木的評論,還有一種非REPL的編譯方式,比如要編譯hive項目,我們可以直接在Spark源碼目錄下執行build/sbt hive/package

使用sbt執行單個測試

示例:build/sbt "~catalyst/test-only *FoldablePropagationSuite"

對catalyst項目執行測試,只測試FoldablePropagationSuite結尾的類。

~是對開發非常有用的東西,他表示進行持續測試,如果我們執行測試后發現case沒有過,那么可以在不退出測試的情況下,直接去修改代碼,保存代碼后,sbt會再次執行測試。

如果需要對一個子項目執行測試,只需要執行:build/sbt sql/test(對sql項目做測試)。

結語

這下可以爽爽的編譯Spark了。

還有一些有用的編譯技巧,去參考http://spark.apache.org/developer-tools.html就可以了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM