bazel
2016-05-13 26 views 3 likes 
3

的谷歌巴澤勒構建工具可以很容易足以說明,在一個特定的目錄樹中的每個CoffeeScript的文件需要被編譯成相應的輸出的JavaScript文件:可以將需要重建的N個M文件批量批處理成單個命令嗎?

# Runs "coffee" 100 times if there are 100 files: 
# will run slowly if most of them need rebuilding. 

[genrule(
    name = 'compile-' + f, 
    srcs = [f], 
    outs = [f.replace('src/', 'static/').replace('.coffee', '.js')], 
    cmd = 'coffee --compile --map --output $$(dirname [email protected]) $<', 
) for f in glob(['src/**/*.coffee'])] 

但考慮,比方說,100個的CoffeeScript文件,這將分開調用咖啡工具100,爲編譯過程增加許多秒。

或者,這可以寫成一個單一的命令,需要100個文件作爲輸入,併產生100個文件作爲輸出:

# Runs "coffee" once on all the files: 
# very slow in the case that only 1 file was edited. 

coffee_files = glob(['src/**/*.coffee']) 

genrule(
    name = 'compile-coffee-files', 
    srcs = coffee_files, 
    outs = [f.replace('src/', 'static/').replace('.coffee', '.js') for f in coffee_files], 
    cmd = 'coffee --compile --map --output @D $(SRCS)', 
) 

有什麼辦法來解釋BAZEL咖啡可以用許多文件被調用並且如果N個目標已過期,那麼只有N個源文件應該提供給coffee命令,而不是所有目標的完整列表,而不管它們是否需要重建?

回答

3

coffeescript文件是否相互獨立?如果第一個工作,其中每個文件分別通過coffee運行,那麼看起來如此。在這種情況下,第一個實際上會給你最平行和漸進的。

即使咖啡100次的運行速度比100次運行咖啡的速度慢100次,您只會在第一次編譯所有內容時支付這筆費用。當您更改1個文件時,其他99個將不會重新編譯。但是,如果coffee的啓動時間如此之長以至於100個文件實際上可以忽略不計,那麼您最好還是堅持將它們全部編譯成一個大的啓發式文件。在兩個極端之間妥協

一種方法是創建宏:http://bazel.io/docs/skylark/macros.html

def compile_coffee(name, srcs): 
    native.genrule(
    name = name, 
    srcs = srcs, 
    outs = [f.replace('src/', 'static/').replace('.coffee', '.js') for f in srcs], 
    cmd = 'coffee --compile --map --output @D $(SRCS)', 
) 

,然後你可以使用compile_coffee宏放在構建文件,組織你的構建成適當大小的目標:

load("//pkg/path/to:coffee.bzl", "compile_coffee") 

compile_coffee(
    name = "lib", 
    srcs = glob(["*.coffee"])) 

還有完整的雲雀規則:http://bazel.io/docs/skylark/rules.html但是,如果咖啡腳本文件並不真正相互依賴,那麼這可能不是必需的。

還有一些持續的工作人員:http://bazel.io/blog/2015/12/10/java-workers.html它允許您保持一個正在運行的咖啡實例,以便您不必支付啓動成本,但二進制文件必須表現良好,並且更多一些因爲你通常必須編寫包裝器才能將所有東西連接起來。

0

這將在同一時間通過20個文件到CoffeeScript的編譯器:

BUILD

load(":myrules.bzl", "coffeescript") 

coffee_files = glob(["src/*.coffee"]) 

# 'coffeescript' is a macro, but it will make a target named 'main' 
coffeescript(
    name = "main", 
    srcs = coffee_files 
) 

myrules.bzl

def _chunks(l, n): 
    n = max(1, n) 
    return [l[i:i+n] for i in range(0, len(l), n)] 

def coffeescript(name, srcs): 
    i = 0 
    all_outs = [] 
    for chunk in _chunks(srcs, 20): 
     chunk_name = "{}-{}".format(name, i) 
     outs = [f.replace('src/', 'static/').replace('.coffee', '.js') for f in chunk] + \ 
       [f.replace('src/', 'static/').replace('.coffee', '.js.map') for f in chunk] 
     all_outs += outs 
     native.genrule(
      name = chunk_name, 
      srcs = chunk, 
      outs = outs, 
      cmd = "coffee --compile --map --output $(@D)/static $(SRCS)" 
     ) 
     i += 1 

    # make a filegroup with the original name that groups together all 
    # of the output files 
    native.filegroup(
     name = name, 
     srcs = all_outs, 
    ) 

然後,bazel build :main將建立所有的CoffeeScript文件,20一次。

但是,這確實有一些弱點:

  • 如果一個CoffeeScript的文件被修改,那麼20將得到重新編譯。不只是一個。

  • 如果文件被添加或刪除,那麼很多文件 - 基本上是從那一點直到文件列表的末尾 - 將被重新編譯。

我發現最好的方法是做什麼@ahumesky建議:把任務分配合理大小巴澤爾「套餐」,讓每個包做一個單一的彙編。

相關問題