成年人福利视频_精品一区二区三区免费播放_日韩三级国产_日本久久网_亚洲精品天堂在线_人人搞人人爽_国产99热_欧美午夜在线播放_亚洲精品字幕在线_又爽又大久久久级淫片毛片_午夜精品久久久久久久男人的天堂_糖心vlog在线观看免费_成人无码专区免费播放三区_久久久久久久久嫩草精品乱码_亚洲va在线va天堂va偷拍_精品日本一区二区三区_国产在线1区_俄罗斯av网站_久久国产日韩_日本久久中文

二維碼
企資網(wǎng)

掃一掃關注

當前位置: 首頁 » 企業(yè)資訊 » 資訊 » 正文

Swift_與_Objective_C_混編

放大字體  縮小字體 發(fā)布日期:2021-09-05 02:29:59    作者:企資小編    瀏覽次數(shù):92
導讀

作者 | 趙志、曾慶隆、顧夢奇、王強、趙發(fā)出品 | CSDN(ID:CSDNnews)2019 年 3 月 25 日,蘋果發(fā)布了 Swift 5.0 版本,宣布了 ABI 穩(wěn)定,并且Swift runtime 和標準庫已經(jīng)植入系統(tǒng)中,而且蘋果新出文檔都用 Swift,

作者 | 趙志、曾慶隆、顧夢奇、王強、趙發(fā)

出品 | CSDN(ID:CSDNnews)

2019 年 3 月 25 日,蘋果發(fā)布了 Swift 5.0 版本,宣布了 ABI 穩(wěn)定,并且Swift runtime 和標準庫已經(jīng)植入系統(tǒng)中,而且蘋果新出文檔都用 Swift,Sample Code 也是 Swift,可以看出 Swift 是蘋果扶持與研發(fā)的重點方向。

目前國內(nèi)外各大公司都在相繼試水,只要關注 Swift 在國內(nèi) iOS 生態(tài)圈現(xiàn)狀,你就會發(fā)現(xiàn),Swift 在國內(nèi) App 應用的比重逐漸升高。對于新 App 來說,可以直接用純 Swift 進行開發(fā),而對于老 App 來說,絕大部分以前都是用 OC 開發(fā)的,因此 Swift/OC 混編是一個必然面臨的問題。

CSDN 付費下載自視覺中國

Swift 和 OC 混編開發(fā)

關于 Swift 和 OC 間如何混編,業(yè)內(nèi)也已經(jīng)有很多相關文章詳細講解,簡單來說 OC/Swift 調(diào)用 Swift,最終通過 Swift Module 進行,而 Swift 調(diào)用 OC 時,則是通過 Clang Module,當然也可以通過 Clang Module 進行 OC 對 OC 的調(diào)用。58同城于 2020 年正式上線首個 Swift/OC(Objective-C,以下簡稱 OC)項目,與此同時,也在全公司范圍內(nèi)開展了一個多部門協(xié)作項目——混天項目,主要目標:

一是提供混編的基礎設施建設,如提供通過的 Module 化方案;

二是擴展各工具鏈的混編能力,如對無用類檢測工具 WBBlades(github/wuba/WBBlades)進行 Swift 能力的擴展;

三是對已有的基礎庫進行 Module 化和 Swift 適配;

四是將混編開發(fā)在各 App 和各業(yè)務線中推廣和落地。

我們在 Module 化實踐中發(fā)現(xiàn),實際數(shù)據(jù)與蘋果官方 Module 編譯時間數(shù)據(jù)不一致,于是我們通過 Clang 源碼和數(shù)據(jù)相結合的方式對 Clang Module進行了深入研究,找到了耗時的原因。由于 Swift/OC 混編下需要 Module 化的支持,同時借鑒業(yè)內(nèi) HeaderMap 方案讓 OC 調(diào)用 OC 時避開 Module 化調(diào)用,將編譯時間優(yōu)化了約 35%,較好地解決了在 Module 化下的編譯時間問題。

Clang Module 初探

Clang Module 在 2012 LLVM Developers Meeting 上第一次被提出,主要用來解決 C 語言預處理的各種問題。Modules 試圖通過隔離特定庫的接口并且編譯一次生成高效的序列化文件來避免 C 預處理器重復解析 Header 的問題。在探究 Clang Module 之前,我們先了解一下預處理的前世今生。

一個源代碼文件到經(jīng)過編譯輸出為目標文件主要分為下面幾個階段:

源文件在經(jīng)過 Clang 前端包含:詞法分析(Lexical analysis) 、語法分析(Syntactic analysis) 、語義分析(Semantic analysis)。最后輸出與平臺無關的 IR(LLVM IR generator)進而交給后端進行優(yōu)化生成匯編輸出目標文件。

詞法分析(Lexical analysis)作為前端的第一個步驟負責處理源代碼的文本輸入,具體步驟就是將語言結構拆分為一組單詞和記號(token),跳過注釋,空格等無意義的字符,并將一些保留關鍵字轉義為定義好的類型。詞法分析過程中遇到源代碼 “#“ 的字符,且該字符在源代碼行的起始位置,則認為它是一個預處理指令,會調(diào)用預處理器(Preprocessor)處理后續(xù)。在開發(fā)中引入外部文件的 include/import 指令,定義宏 define 等指令均是在預處理階段交由預處理器進行處理。Clang Module 機制的引入帶來的改變著重于解決常規(guī)預處理階段的問題,那么跟隨我們一起來重點探究一下其中的區(qū)別和實現(xiàn)原理吧!

2.1 普通 import 的機制

Clang Module 機制引入之前,在日常開發(fā)中,如果需要在源代碼中引入外部的一些定義或者聲明,常見的做法就是使用 #import 指令來使用外部的 API。那么這些使用的方式在預處理階段是怎么處理的呢?

針對編譯器遇到 #import<PodName/header.h> 或者 #import ”header.h” 這種導入方式時候,# 開頭在詞法分析階段會觸發(fā)預處理(Preprocessor)。而對于 Clang 的預處理器 import 與 include 指令都屬于它的關鍵詞。預處理器在處理 import Directive 時候主要工作為通過導入的 header 名稱去查找文件的磁盤所在路徑,然后進入該文件創(chuàng)建新的詞法分析器對導入的頭文件進行詞法分析。

如下所示:編譯器在遇到 #import 或者 #include 指令時,觸發(fā)預處理機制查詢頭文件的路徑,進入頭文件對頭文件的內(nèi)容進行解析的流程。

以單個文件編譯過程為維度舉例:在針對一個文件編譯輸出目標文件的過程中,可能會引入多個外界的頭文件,而被引入多個外界頭文件也有可能存在引入外界頭文件。這樣的情況就導致雖然只是在編譯單個文件,但是預處理器會對引入的頭文件進行層層展開。這也是很多人稱 #import 與 include 是一種特殊“復制”效果的原因。

那么在這種預處理器的機制在工程中編譯中會存在什么問題呢?蘋果官方在 2012 的 WWDC 視頻上同樣給了我們解答:Header Fragility (健壯性)和 Inherently Non-Scalable (不可擴展性)。

來看下面一段代碼,在 PodBTestObj 類的文件中定義一個 ClassName 字符串的宏,然后在導入 PoBClass1.h 頭文件,在 PoBClass1.h 的頭文件中同樣定義一個結構體名為 ClassName,這里與我們在 PodBTestObj 類中定義的宏同名。預處理的特殊的“復制”機制,在預處理階段會發(fā)生下圖所見的結果:

這樣的問題相信在日常開發(fā)中并不罕見,而為了解決這種重名的問題,我們常規(guī)的手法只能通過增加前綴或者提前約定規(guī)則等方式來解決。

視頻中同時指出這種機制在應對大型工程編譯過程中的所帶來的消耗問題。假設有 N 個源文件的工程,那么每個源文件引用 M 個頭文件,由于預處理的這種機制,我們在針對處理每個源文件的編譯過程中會對引入的 M 個頭文件進行展開,經(jīng)歷一遍遍的詞法分析-語法分析-語義分析的過程。那么你能想象一下針對系統(tǒng)頭文件的引入在預處理階段將會是一個多么龐大的開銷!

那么針對 C 語言預處理器存在的問題,蘋果有哪些方案可以優(yōu)化這些存在的問題呢?

2.2 PCH (Precompiled Headers)

PCH(Precompile Prefix Header File)文件,也就是預編譯頭文件,其文件里的內(nèi)容能被項目中的其他所有源文件訪問。日常開發(fā)中,通常放一些通用的宏和頭文件,方便編寫代碼,提高效率。

關于 PCH 的概述,蘋果是這樣定義的:

which uses a serialized representation of Clang’s internal data structures, encoded with the LLVM bitstream format.

(使用 Clang 內(nèi)部數(shù)據(jù)結構序列化表示,采用的 LLVM 字節(jié)流表示)。

它的設計理念當項目中幾乎每個源文件中都包含一組通用的頭文件時,將該組頭文件寫入 PCH 文件中。在編譯項目中的流程中,每個源文件的處理都會首先去加載 PCH 文件的內(nèi)容,所以一旦 PCH 編譯完成,后續(xù)源文件在處理引入的外部文件時候會復用 PCH 編譯后的內(nèi)容,從而加快編譯速度。PCH 文件中存放我們所需要的外部頭文件的信息(包括不局限于聲明、定義等)。它以特殊二進制形式進行存儲,而在每個源代碼編譯處理外部頭文件信息時候,不需要每次進行頭文件的展開和“復制”重復操作。而只需要“懶加載”預編譯好的 PCH 內(nèi)容即可。

存儲內(nèi)容方面它存放著序列化的 AST 文件。AST 文件本身包含 Clang 的抽象語法樹和支持數(shù)據(jù)結構的序列化表示,它們使用與 LLVM’s bitcode file format. 相同的壓縮位流進行存儲。關于 AST File 文件的存儲結構你可以在官方文檔有詳細的了解。

它作為蘋果一種優(yōu)化方案被提出,但是實際的工程中源代碼的引用關系是很復雜的,所以找出一組幾乎所有源文件都包含的頭文件基本不可能,同時對于代碼更新維護更是一個挑戰(zhàn)。其次在被包含頭文件改動下,因為 PCH 會被所有源文件引入,會帶來代碼“污染”的問題。同時一旦 PCH 文件發(fā)生改動,會導致大面積的源代碼重編造成編譯時間的浪費。

2.3 Modules

上述我們簡單回顧了一些 C 語言預處理的機制以及為解決編譯消耗引入 PCH 的方案,但是在一定程度上 PCH 方案也存在很大的缺陷。因此在 2012 LLVM Developer’s Meeting 首次提出了 Modules 的概念。

那么 Module 到底是什么呢?

Module 簡單來說可以認為它是對一個組件的抽象描述,包含組件的接口和實現(xiàn)。Module 機制推出主要用來解決上述所闡述的預處理問題,想要探究 Clang Module 的實現(xiàn),首先需要去開啟 Module。那么針對 iOS 工程怎么開啟 Module 呢? 只需要打開編譯選項中:

對!你沒看錯,僅僅需要在 Xcode 的編譯選項中修改配置即可。

而在代碼的使用上幾乎可以不用修改代碼,開啟 Module 之后,通過引用頭文件的方式可以繼續(xù)沿用 #import <PodName/Header.h> 方式。當然對于開發(fā)者也可以采用新的方式 @import ModuleName.SubModuleName,以及 @import ModuleName這幾種方式。更為詳細的信息和使用方法可以在蘋果的官方文檔中查看。

2.4 蘋果對 Module 的解讀

上文提到過基于 C 語言預處理器提供的 #include 機制提供的訪問外界庫 API 的方式存在的伸縮性和健壯性的問題。Modules 提供了更為健壯,更高效的語義模型來替換之前 textual preprocessor 改進對庫的 API 訪問方式。

蘋果官方文檔中針對 Module 的解讀有以下幾個優(yōu)勢:

擴展性:每個 Module 只會編譯一次,將 Module 導入 Translantion unit 的時間是恒定的。對于庫 API 的訪問只會解析一次,將 #include 的機制下的由 M x N 編譯問題簡化為 M + N。

健壯性:每個 Module 作為一個獨立的實體,具備一個一致的預處理環(huán)境。不需要去添加下劃線,或者前綴等方式解決命名的問題。每個庫不會影響另外一個庫的編譯方式。

我們翻閱了蘋果 WWDC 2013 的 Advances in Objective-C 視頻,視頻中針對編譯時間性能方面進行了 PCH 和 Module 編譯速度的數(shù)據(jù)分析。蘋果給出的結論是小項目中 Module 比 PCH 能提升 40% 的編譯時間,并且隨著工程規(guī)模的不斷增大,如增大到 Xcode 級別,Module 的編譯速度也會比 PCH 稍快。PCH 也是為了加速編譯而存在的,由此也可以間接得出結論,Module的編譯速度要比沒有 PCH 的情況下,是更快的,如在 Mail 下,應該提升 40% 以上。

對 Clang Module 機制建立一定的認知上,我們著手進行了 Clang Module 在 58同城 App 上的 Module 化改造。

58同城初步實踐

3.1 Module 化工程配置

組件 Module 化

在多 pod 的項目中,通過以下幾種方式可以將各 pod 進行 Module 化:

    Podfile 中添加 use_modular_headers! 對所有的 pod 進行 Module 化;

    Podfile 中通過 modular_headers 對每個 pod 單獨進行 Module 化,如對 PodC 進行 Module 化,pod 'PodC', :path => '../PodC',:modular_headers => true;

    在 pod 所對應的 .podspecs 中的 xcconfig 中 sg 配置 DEFINES_MODULE,如 s.xcconfig = {'DEFINES_MODULE' => 'YES'}。

此外,為了能讓其它組件能通過 module 方式引用 Module 化的組件,還需要設置它們之前的依賴關系。

在58同城中,維護了一個全局的依賴配置文件 dependency.json,這個文件通過自動化工具進行維護,各組件 pod 的 .podspecs 從 dependency.json 中動態(tài)讀取自己依賴的其它組件,并生成相應的 dependency 關系。

3.2 Swift/OC 混編橋接文件

通常在 Swift/OC 混編工程中會自動或手動在當前pod添加加一個橋接文件,如 PodC-Bridging-Header.h,配置當前 pod 中 Swift 需要引用的 OC 文件,形式如下所示。

這樣可以達到編譯的目的,但是由于依賴的組件都是在橋接文件中統(tǒng)一配置,對于每個 Swift 文件依賴了哪些 pod 組件,實際上并不清楚,而且 Swift 中每次修改新增一個 OC 文件的引用,都需要在橋接文件中進行修改,并且如果是減少對某個 OC 文件的引用,也不好確定是否要在橋接文件中進行刪除,因為還需要判斷其它 Swift 文件中是否有引用。

Swift 文件中可以通過 module 的方式去引用 OC 文件,因此,如果所依賴 OC 文件的 pod 都 Module 化后,可以通過 import module 的方式進行引用,每個 Swift 文件各自維護對外部 pod 的依賴,從而將 XXX-Bridging-Header.h 文件刪除,也減少了對橋接文件的維護成本。

3.3 同城的 Module 化編譯數(shù)據(jù)

萬事具備,只差編譯!

結合蘋果官方給出了性能數(shù)據(jù),我們預測 Module 化后的編譯速度是要比非 Module 情況更快,那不妨就編譯試試,接下來在 58同城中分別在 module 和非 module 場景下進行編譯。

通過編譯數(shù)據(jù),我們看到的結果發(fā)生了逆轉,Module 化之后的時間竟然比非 Module 情況下長約 8%,這跟剛才我們看到的蘋果官方數(shù)據(jù)不符,有點亂了。需要說明的是這份數(shù)據(jù)是 58同城全業(yè)務線在 M1 機器上運行出來的,并且把資源復制的環(huán)節(jié)從配置中刪除了,即不包含資源復制時間,是純代碼編譯時間,并且在非 M1 機器上也運行了進行對比,除了時間長些,結論基本也是 module 化之后時間長 10% 左右。

在面對實際測試結果 Module 化之后的編譯耗時更長的情況下,我們從更深層次上進行對 Clang Module 原理進行了探究。

Clang Module 原理深究

Clang Module 機制的引入主要是為了解決預處理器的各種問題,那么工程在開啟 Module 之后,工程上會有哪些變化呢?同時在編譯過程中編譯器工作流程與之前又有哪些不同呢?

4.1 ModuleMap 與 Umbrella

以基于 cocoapods 作為組件化管理工具為例,開啟 Module 之后工程上帶來最直觀的改變是pod組件下 Support Files 目錄新增幾個文件:podxxx.moduleMap , podxxx-umbrella.h。

Clang 官方文檔指出如果要支持 Module,必須提供一個 ModuleMap 文件用來描述從頭文件到模塊邏輯結構的映射關系。ModuleMap 文件的書寫使用 Module Map Language。通過示例可以發(fā)現(xiàn)它定義了 Module 的名字,umbrella header 包含了其目錄下的所有頭文件。module * 該通配符的作用是為每個頭文件創(chuàng)建一個 subModule。

簡單來說,我們可以認為 ModuleMap 文件為編譯器提供了構建 Clang Module 的一張地圖。它描述了我們要構建的 Module 的名稱以及 Module 結構中要暴露供外界訪問的 API。為編譯器構建 Module 提供必要條件。

除了上述開啟 Module 的組件會新增 ModuleMap 與 Umbrella 文件之外。在使用開啟 Module 的組件時候也有一些改變,使用 Module 組件的 target 中 BuildSetting 中 Other C Flag 中會增加 -fmodule-map-file 的參數(shù)。

蘋果官方文章中對該參數(shù)的解釋為:

Load the given module map file if a header from its directory or one of its subdirectories is loaded.

(當我們加載一個頭文件屬于 ModuleMap 的目錄或者子目錄則去加載 ModuleMap File)。

4.2 Module 的構建

了解完 ModuleMap 與 Umbrella 文件和新增的參數(shù)之后,我們決定深入去跟蹤一下這些文件與參數(shù)的在編譯期間的使用。

上文提到過在詞法分析階段以“#”開頭的預處理指令,我們對針對 HeaderName 文件進行真實路徑查找,并對要導入的文件進行同樣的詞法,語法,語義等操作。在開啟 Module 化之后,頭文件查找流程與之前有什么區(qū)別呢?在不修改代碼的基礎上編譯器又是怎么識別為語義化模型導入(Module import)呢?

如下圖所示:在初始化預處理之前,會針對 buildsetting 中設置的 Header Search path,framework Search Path 等編譯參數(shù)解析賦值給 SearchDirs。

在 Clang 的源碼中 Header Search 類負責具體頭文件的查找工作,Header Search 類中持有的 SearchDirs 存放著當前編譯文件所需要的頭文件搜索路徑。其中對于一個頭文件的搜索分三種情況:hmap, Header Search Path 以及 frameworks search path。而 SearchDirs 的賦值發(fā)生在編譯實體(CompilerInstance)初始化預處理器時,而這些參數(shù)的來源則是在 Xcode 工程 Buildsetting 中的相關編譯參數(shù)。

編譯器在查詢頭文件具體磁盤路徑的過程中,會通過 Header.h 或者 PodName/Header.h 與 SearchDirs 集合中的路徑拼接判斷該路徑下是否存在我們要查找的頭文件。當前循環(huán)的 SearchDirs 對應的元素中根據(jù)類型:(Header Search Path,frameworks,HeaderMap)進行相應的查詢流程。

上文提到過針對開啟 Module 的組件不需要額外的修改頭文件導入的代碼,編譯器自動識別我們的頭文件導入是否屬于 Module,而判斷 Header 導入是否屬于 Module import 就發(fā)生在查找頭文件路徑中。上述代碼我們會注意到針對 framework 與常規(guī)的目錄查找中,會透傳一個參數(shù) SuggestedModule。

我們進一步向下跟蹤 SuggestModule 的賦值過程,在查找到頭文件的磁盤路徑之后,編譯器會進行該文件目錄或者父級目錄路徑作為 Key 去 UmbrellaDirs 查找該頭文件的是否有對應的 Module 存在。如果能查詢到則賦值 SuggestModule(ModuleMap::KnownHader(Module *,NormalHeader) )。下圖為查詢并賦值 SuggestModule 的流程。

相信你看到上面的源碼,你又會出現(xiàn)新的疑惑。UmbrellaDirs 是什么?前面提到過使用開啟 Module 組件的 Target 中會新增 -fmodule-map-file 的參數(shù),編譯器在解析編譯參數(shù)時加載 MoudleMapFile,讀取使用 Module Map Language 書寫的 ModuleMap 文件,解析文件的內(nèi)容。

編譯器在編譯工程源代碼時候通過 -fmodule-map-file 參數(shù)讀取我們要使用的 Module,并把 ModuleMap 文件所在的路徑作為 key,我們要使用的 Module 作為 Value,賦值給 UmbrellaDirs。預處理器在解析外界引入的頭文件時候,會判斷頭文件路徑下或者頭文件路徑父級目錄是否存在 ModuleMap 文件,如果存在則 SuggestModule 有值。頭文件查找的流程至此結束。

SuggestModule 的值是編譯器決定使用 Module import 還是“文本導入” 的關鍵因素。預處理器處理頭文件導入,會去查找頭文件在磁盤上的絕對路徑,如果 SuggestModule 有值,編譯器會調(diào)用 ModuleLoader 加載需要的 Module,而不開啟 Module 的組件頭文件,編譯器則會進入該文件進行新的詞法分析等流程。

至此,相信讀到這里大家對 ModuleMap、Umbrella 文件以及 -fmodule-map-path 有了一定的認知。而且我們也跟蹤了為什么編譯器可以做到不修改代碼的“智能”的幫助代碼在 # import 和 Module import 之間切換。

與非 module 不同,我們來繼續(xù)追蹤一下 LoadModule 的后續(xù)發(fā)生了什么?ModuleLoader 進行指定的 Module 的加載,而這里的 LoadModule 正是 Module 機制的差異之處。

Module 的編譯與加載是在第一次遇到 Moduleimport 類型的 importAction 時候進行緩存查找和加載,Module 的編譯依賴 moduleMap 文件的存在,也是編譯器編譯 Module 的讀取文件的入口,編譯器在查找過程中命中不了緩存,則會在開啟新的 compilerInstance,并具備新的預處理上下文,處理該 Module 下的頭文件。產(chǎn)生抽象語法樹然后以二進制形式持久化保存到后綴為 .pcm 的文件中(有關 pcm 文件后文有詳細講解),遇到需要 Module 導入的地方反序列化 PCM 文件中的 AST 內(nèi)容,將需要的 Type 定義,聲明等節(jié)點加載到當前的翻譯單元中。

Module 持有對 Module 構建中每個頭文件的引用,如果其中任何一個頭文件發(fā)生變化,或者 Module 依賴的任何 Module 發(fā)生變化,則該 Module 會自動重新編譯,該過程不需要開發(fā)人員干預。

4.3 Clang Module 復用機制

Clang Module 機制的引入,不僅僅從之前的“文本復制”到語義化模型導入的轉變。它的設計理念同時也著重在復用機制,做到一次編譯寫入緩存 PCM 文件在此后其他的編譯實體中復用緩存。關于 Module 都是編譯和緩存探究的驗證,我們可以在 build log 中通過 -fmodules-cache-path 來查看獲取到 Module 緩存路徑(eg:/Users/xxx/Library/Developer/Xcode/DerivedData/ModuleCache.noindex/ )。當前如果你想自定義緩存路徑可以通過添加 -fmodules-cache-path 指定緩存路徑。

我們知道針對組件化工程,我們每個 pod 庫都可能存在復雜的依賴關系,以某工程示例:

在多組件工程中,我們會發(fā)現(xiàn)不同的組件之間會存在相同的依賴情況。針對復雜的 Module 依賴的場景,通過 Clang源碼發(fā)現(xiàn),在編譯 Module-lifeCirclePod(上述示例)時候,而 lifeCirclePod 依賴于 Module-UIKitPod。在編譯 Module-lifeCirclePod 遇到需要 Module-UIKitPod 導入時,那么此時則會掛起該編譯實體的線程,開辟新的線程進行 Module-UIKitPod 的編譯。

當 Module-UIKitPod 編譯完成時候才會恢復 lifeCirclePod 的任務。而開啟 Module 之后每個組件都會作為一個 Module 編譯并緩存,而當 MainPagePod 后續(xù)編譯過程中遇到 Module-UIKitPodModule 的導入時,復用機制就可以觸發(fā)。編譯器可以通過讀取 pcm 文件,反序列化 AST 文件直接使用。編譯器不用每次重復的去解析外界頭文件內(nèi)容。

上述基本對 Module 的本質(zhì)及其復用機制有一定的了解,是不是無腦開啟 Moudle 就可以了呢?

其實不然!

我們在實踐中發(fā)現(xiàn)(以基于 cocoapods 管理為例)在 fmodules-cache-path 的路徑下存在很多份的 pcm 緩存文件,針對同一個工程就會發(fā)現(xiàn)存在多個下面的現(xiàn)象:

可以發(fā)現(xiàn)在工程的一次編譯下,會出現(xiàn)多個目錄出現(xiàn)同一個 module 的緩存情況(eg:lifeCirclePod-1EBT2E5N8K8FN.pcm)。之前講過 Module 機制是一次編譯后續(xù)復用的嗎?實際情況好像與我們的理論沖突!這就要求我們?nèi)ド钊胩骄?Module 復用的機制。

追尋 Clang 的源碼發(fā)現(xiàn)編譯器進行預處理器 Preprocessor 的創(chuàng)建時,會根據(jù)自身工程的參數(shù)來設定 Module 緩存的路徑。

我們將影響 Module 緩存的產(chǎn)生的 hash 目錄的主要受編譯參數(shù)分為下面幾大類:

在實際的工程中,常常不同 pod 間的 build settting 不同,導致在編譯過程中會生成不同的 hash 目錄,從而緩存查找時候會出現(xiàn)查找不到 pcm 緩存而重復生成 Module 緩存的現(xiàn)象。這也解釋了我們上面發(fā)現(xiàn)不同的緩存 hash 目錄下會出現(xiàn)相同名字的 pcm 緩存。了解 Module 緩存的因素可以有助于在復雜的工程場景中,提高 Module 的復用率減少 Module Complier 的時間。

Tips:除了上述的緩存 hash 目錄外,我們會發(fā)現(xiàn)在目錄下存在以 ModuleName-hashxxxxxx.pcm 的命名,那么緩存文件的命名方式我們發(fā)現(xiàn)是 ModuleName+hash 值的方式,hash 值的生成來自 ModuleMap 文件的路徑,所以保持工程路徑的一致性也是 Module 復用的關鍵因素。

4.3 PCM

上文提到了一個很重要的文件 PCM,那么 PCM 文件作為 Module 的緩存存放,它的內(nèi)容又是怎么樣的呢?

提到 PCM 文件,我們第一時間很容易聯(lián)想到 PCH。PCH 文件的應用大家應該都很熟悉,根據(jù)蘋果在介紹 PCH 的官方文檔中結構如下:

PCH 中存放著不同的模塊,每個模塊都包含 Clang 內(nèi)部數(shù)據(jù)的序列化表示。采用 LLVM’s bitstream format 的方式存儲。其中 metadata 塊主要用于驗證 AST 文件的使用;SourceManager 塊它是前端 SourceManager 類的序列化,它主要用來維護 SourceLocation 到源文件或者宏實例化的實際行/列的映射關系;Types: 包含 TranslationUnit 引用的所有類型的序列化數(shù)據(jù),在 Clang 類型節(jié)點中,每個節(jié)點都有對應的類型;Declarations: 包含 TranslationUnit 引用的所有聲明的序列化表示;Identifier Table: 它包含一個 hash Table,該表記錄了 ASTfile 中每個標識符到標識符信息的序列化表示;Method Pool: 它與 Identifier Table 類似,也是 Hash Table,提供了 OC 中方法選擇器和具體類方法和實例方方法的映射。Module 實現(xiàn)機制與 PCH 相同,也是序列化的 AST 文件,我們可以通過 llvm-bcanalyzer 把 pcm 文件的內(nèi)容 dump 出來。

Module 的編譯是在獨立的線程,獨立的編譯實體過程,與我們輸出目標文件對應的前端 action 不同,它所對應的FrontAction為GenerateModuleAction。Module 的機制思想主要是提供一種語義化的模塊導入方式。所以 PCM 的緩存內(nèi)容同樣會經(jīng)過詞法,語法,語義分析的過程,PCM 文件中的 AST 模塊的序列化保存是在發(fā)現(xiàn)在語義分析之后。

它利用了 Clang AST 基類中的 ASTConsumer 類,該類提供了若干可以 override 的方法,用來接收 AST 解析過程中的回調(diào),當編譯單元TranslationUnit的AST完整解析后,我們可以通過調(diào)用 HandleTranslationUnit 在獲取到完整抽象語法樹上的所有節(jié)點。PCM 文件的寫入由 ASTWriter 類提供 API,這些具體的流程我們可以在 ASTWriter 類中具體跟蹤。在該過程中主要分為 ControlBlock 信息的寫入,該步驟包含 metadata, InputFiles,Header search path 等信息的記錄。這些 PCM 的具體內(nèi)容 dump 出來如下圖:

其中 Types,Declarations 等信息的寫入流程發(fā)生在 ASTBlock 階段。由于在處理處理 ModuleMap 文件的編譯流程中會對 umbrella.h 中所暴露的頭文件進行預處理,詞法,語法,語義分析等流程。我們在使用 WriteAST 寫入時,會將當前編譯實體的 Sema 類(該類是 build AST 和語義分析的實現(xiàn)類)傳遞過來。Sema 持有當前的 ASTContext,ASTContext 則可以用于訪問當前抽象語法樹上的所有 Nodes(例如 types,decls)等信息。

如果所示:ASTWriter 將已經(jīng)解析無誤的 Module 信息,包括 AST 等內(nèi)容寫入 Module 的緩存文件 PCM 中。

我們在源碼跟蹤過程中可以發(fā)現(xiàn)會將AST節(jié)點信息等寫入PCM中的ASTBlock中,我們可以通過打印獲取到節(jié)點的類型和節(jié)點的名稱:

通過上面源碼等流程相信你掌握了以下:

ModuleMap 文件用來描述從頭文件到模塊邏輯結構的映射關系,Umbrella 或者Umbrella Header 描述了子Module的概念;

Module 的構建是“獨立”進行的,Module 間存在依賴時,優(yōu)先編譯完成被依賴的Module;

Clang 提供了 Module 的新用法(@import ModuleName),但是針對就項目無需改造,Clang 在預處理時期提供了 Module 與非 Module 的轉換;

Module 提供了復用的機制,它將暴露外界的 API 以 ASTFile 格式存儲,在代碼未發(fā)生變化時,直接讀取緩存。而在代碼變動時,Xcode 會在合適的時機對 Module 進行更新,開發(fā)者無需額外干預。

同城編譯時間數(shù)據(jù)分析

鑒于在58同城工程上實施的編譯數(shù)據(jù)時間的加長的背景,我們在深入探究 Module 構建,復用等機制后,我們針對整個編譯流程做了詳細的編譯階段的插樁。

5.1 分析工具

Clang 9.0 合并了一個非常有用的功能 -ftime-trace,該功能允許以友好的格式生成時間跟蹤分析數(shù)據(jù),clang中預先插入了一些點標記,如每個文件的編譯時間ExecuteCompiler、前端編譯時間Frontend、module加載時間Module Load、后端處理時間Backend等。接下來通過-ftime-trace查看各編譯階段的打點時間。操作比較簡單,只需要在Other C Flags中添加-ftime-trace即可。

編譯完成后clang會在編譯目錄下,為每個源文件自動生成一個json文件,文件名和源碼文件相同。

每個json文件中大概會有ExecuteCompiler、Frontend、Source、Module Load、Backend等打點數(shù)據(jù),也有Total ExecuteCompiler、Total Frontend、Total Source、Total Module Load、Total Backend這樣的數(shù)據(jù),后者是前者的一個匯總,這是clang自帶的,也可以在clang中去擴展。通過chrome://tracing/可以很方便查看單個json文件的耗時分布,如下。

-ftime-trace設置后主要時間段說明:

Total ExecuteCompiler:文件編譯總時間;

Total Frontend:前端編譯時間,如在clang中編譯時間;

Total Source:頭文件處理時間,如處理import;

Total Module Load:Module的加載時間,如在Source的處理過程中,判斷當前import的是一個module,則會執(zhí)行此操作,如import系統(tǒng)庫;

Total Module Compile:Module的編譯時間,如第一次加載自定義的源碼Module,會對Module進行編譯,生成AST緩存起來;

Total Backend:編譯器后端處理時間。

這些時間段都是Clang中已有的打點,從前面的chrome://tracing/圖也能看出來是有一些包含關系的,如:

    ExecuteCompiler 包含F(xiàn)rontend和Backend;

    Frontend包含Source;

    Source中包含Module Load(前提是如當前.m中import了A/XX.h,而A沒有module化,但XX.h中import了B/YY.h,B是Module化的,如果A是module化的,Module Load不包含在Source中);

    Module Load包含Module Compile。

5.2 時間段分析

先選取單個文件進行分析,將其拖到chrome://tracing/中,可看到如下數(shù)據(jù)。

從圖上可看出,Total Frontend占總編譯時間在都在70%以上,module編譯中Total Frontend時間比非module明顯要長,而Total Source占Total Frontend時間的70%左右,而Total Module Load是Total Source中最耗時的操作。結果中Total Module Load階段,module明顯是要比非module耗時更長。

上面是從單個文件進行分析,并不能代表整體項目的編譯情況,因此,我們做了一個自動化工具,將所有.json文件中的對應時間進行統(tǒng)計匯總,得出整體各個時間段的匯總數(shù)據(jù),如下。說明一下,我們統(tǒng)計的Total ExecuteCompiler指每個文件的編譯時間總和,相當于在單核下編譯時間,而前面顯示的實際整體的編譯時間少很多,是因為我們實際是在多核下編譯。

從整體分析圖上可看出,Total Frontend時間均占總編譯時間Total ExecuteCompiler的80%以上,而Total Frontend中時間Total Source的總時間占80%以上,而在Total Source中Total Module Load時間占70%左右。總時間Total ExecuteCompiler和前端Total Frontend依然是module下更長,而在Total Frontend中Total Module Load的時長在module下明顯比非module下長很多,跟上面單文件分析的結論基本一致。這里需要注意的是,Total ExecuteCompiler時間比前面統(tǒng)計的總時間長很多,是因為項目是在多核下編譯,而Total ExecuteCompiler統(tǒng)計的是所有文件編譯時間總和,而前面統(tǒng)計的時間是多文件并行編譯下的時間,其它各段時間同理。

在Total Module Load中會執(zhí)行Module的編譯,但從上圖我們可以看到其實Total Module Compile時間很短,都不超過50S,因此還需要進一步分析Total Module Load的耗時操作。為此我們根據(jù)clang中的處理流程,在clang中Module Load處理代碼中擴展兩個打點:

Module ReadAST:驗證Module緩存并反序列化Module cache PCM文件的時長;

Module WaitForLock:一個線程在ModuleCompiler期間,其他線程需要掛起等待的時長。

并在頭文件查找擴展打點:

Lookup HeaderFile :預處理階段查找導入頭文件的磁盤路徑時間。

將Clang源碼修改后編譯生成自定義的Clang,替換XCode中的Clang分別在module和非module下再次進行編譯,得出如下數(shù)據(jù):

從圖中可以看出,Module Load階段中Module ReadAST時間占比近70%,此次編譯module比非module下時間長約3%,而Module ReadAST段module比非module下時間長約2%,整個Module Load階段module下比非module下長約4%。

因此,我們可以得出,相比非module,module化編譯更為耗時,而主要耗時在驗證Module緩存并反序列化操作。那么問題來了,有什么辦法可以在module開啟的情況下進行編譯時間優(yōu)化呢?

編譯時間的優(yōu)化

從上面的數(shù)據(jù)分析我們知道,如果底層組件進行 Module 化,并且上層組件通過module方式進行引用的話,會更耗時。但是為了支持 Swift/OC 混編,如 Swift 調(diào)用 OC,需要對組件進行 Module 化。因此,我們需要在 Module 化的基礎上優(yōu)化編譯時間,如果上層組件不通過 Module 方式調(diào)用其它 Module 化的組件,而采用非 Module 化方式進行引用,理論上是能避免上述module化操作的耗時。

6.1 優(yōu)化方案

為了進一步優(yōu)化混編下的編譯時間,我們參考蘋果 WWDC 2018 的 header search path 中 headermap 查找方案,主要思路是通過 hmap 的方式來替換header search path 下的文件搜索,來減少編譯耗時,為描述方便,我們稱為hmap方案,目前業(yè)內(nèi)美團對 hmap 有應用,并且有 50% 的優(yōu)化效果。58同城也對 headermap 方案進行了研究并進行了落地,理想的實現(xiàn)方案就是做一個 cocoapods 插件,在插件中做了以下幾件事:

    HooksManager注冊cocoapods的post_install鉤子;

    通過header_mappings_by_file_accessor遍歷所有頭文件和header_dir,由header_dir/header.h和header.h為key,以頭文件搜索路徑為value,組裝成一個Hash<key,value>,生成所有組件pod頭文件的json文件,再通過hmap工具將json文件轉成hmap文件。

    再修改各pod中.xcconfig文件的HEADER_SEARCH_PATHS值,僅指向生成的hmap文件,刪除原來添加的搜索目錄;

    修改各pod的USE_HEADERMAP值,關閉對默認的hmap文件的訪問。

58對應的插件名為cocoapods-wbhmap,插件完成后,在Podfile中通過plugin 'cocoapods-wbhmap'接入。

6.2 優(yōu)化數(shù)據(jù)

以下是58同城分別在非 Module、Module 化和優(yōu)化后的 hmap 三種場景下編譯時間數(shù)據(jù),這里的 hmap 是在各組件 Module 化的基礎上使用的。

首先說明一下,這里的整體編譯時間數(shù)據(jù)上跟前面不一致,是因為重新編譯了,每次編譯時間略有不同,但不影響我們分析。從整體時間來看 Module 下的編譯時間比非 Module 下略長,而 hmap 比非 Module 下優(yōu)化了 32% 左右,比 Module 下優(yōu)化了 33% 左右,可以看出 hmap 的優(yōu)化效果是很顯著的。

接下來分析一下編譯各階段的時間,是不跟我們預想的一致,我們預想的是 Total Lookup HeaderFile 和 hmap 在 Module Load 階段加載的 Module基本是系統(tǒng)庫,應當時間上差不多,而由于hmap節(jié)省了在眾多目錄下文件搜索的時間,應當在Total Lookup HeaderFile有較大差別。

從分段數(shù)據(jù)來看,三種編譯方式的 Total ExecuteCompiler 跟上述整體時間比例接近,但是 Total Lookup HeaderFile 時間都較小,自然沒多大差別,而 Total Module Load 差別較大,非 Module 和 Module 下比 hmap 大 61% 左右,跟我們預想的不一致。觀察數(shù)據(jù)可以看到,Module Load 中大部分時間是在 Module ReadAST 階段,因而我們繼續(xù)研究 Module ReadAST 中的處理操作。

6.3 hmap 優(yōu)化了什么?

針對 ReadAST 階段再次細分打點計時,發(fā)現(xiàn)在 ReadAST 階段去讀取緩存時候,會對緩存 PCM 文件的 ControlBlock 塊信息進行解析,該內(nèi)容包含了當前 Module 緩存引用外界其他 ASTFile 的記錄。而加載外界 ASTFile 的 PCM 緩存時候,會針對該 ModuleName 進行驗證確保我們不會加載一個 non-Module 的 ASTFile 作為一個 Module。它通過查詢是否存在 ModuleMap 文件來描述 Module 對應當前要查詢的 ModuleName。

我們將重點聚焦在這個階段,因為我們 hmap 方案最直接的優(yōu)化之處在減少了 Header Search Path 的參數(shù)路徑,將預處理期間的頭文件查找轉換為 key-value 查找,從而減少了在 Header Search Path 眾多 pod 的目錄中(如private、public)的搜索時間,源碼中 SearchDirs 即為這些目錄,Header Search Path 中目錄越多,SearchDirs 中元素更多,要遍歷的目錄就更多,無用的搜索時間就越長,通過單個文件進行調(diào)試發(fā)現(xiàn)這里消耗的時間約有 70%,而系統(tǒng)庫的查找在這里耗時較長,因為按照編譯器搜索的順序,系統(tǒng)庫目錄的是排在 Header Search Path 后的,經(jīng)過一頓徒勞的搜索之后才到系統(tǒng)庫目錄搜索,效率較低。

我們猜想前面非 Module 和 hmap 在 Module Load 時間差較大的原因應當就在此,因此在 ReadAST 階段的 HeaderSearch::lookupModule 方法內(nèi)打個點 Lookup Module,即 Module ReadAST 包含 Lookup Module,重新編譯進行數(shù)據(jù)統(tǒng)計如下:

這里只統(tǒng)計非 Module 和 hmap,整體編譯時間如下:

從數(shù)據(jù)可以看出,再次編譯 hmap 下的編譯時間比非 Module 方式同樣是優(yōu)化了 35% 左右。再看分段數(shù)據(jù),如下:

從占比分析,非 Module 方式下 Total Lookup Module 時間占 Total Module ReadAST 時間的 77%,并占 Total Module Load 時間的 72%,而在 hmap 方式中,Total Lookup Module 時間占 Total Module ReadAST 時間的 35%,并占 Total Module Load 時間的 27%,遠小于非 Module 方式下的占比。

從數(shù)值分析,非 Module 方式下 Total Lookup Module 時間為 1422 秒,而 hmap 方式下時間僅為 182 秒,相差 7 倍多。

上面數(shù)據(jù)也進一步驗證了我們對于 hmap 編譯時間優(yōu)化原因的猜想。到這里我們就從數(shù)據(jù)和原理上對 hmap 方案的編譯優(yōu)化做了一個完整的分析。

總結

由于 Swift/OC 混編項目的需要,58同城對組件進行了 Module 化,并且嘗試讓所有組件通過 Module 方式進行頭文件引用。但我們發(fā)現(xiàn)編譯時間卻比非 Module 情況下更長,這也與蘋果官方在 WWDC2013 中的 Module 性能分析結果不符。

然后在尋求編譯時間的優(yōu)化方案時,發(fā)現(xiàn)在 WWDC2018 中有提到 hmap 機制,并借鑒業(yè)內(nèi)的一些寶貴經(jīng)驗,采用了 hmap 方案對編譯時間進行優(yōu)化。Module 方案雖無法降低編譯耗時,但對比之前混編的橋接方式,可增強項目向 Swift 遷移過程中混編組件的可維護性。通過 hmap 方案對編譯時間進行優(yōu)化,同城最終編譯時間比 Module 化之前優(yōu)化了約 35%,對于其它 App 的 Module 化也是有較好的借鑒意義。

作者簡介

趙志:58同城-用戶價值增長部

曾慶隆:58同城-用戶價值增長部

顧夢奇:58同城-房產(chǎn)事業(yè)群

王強:58同城-招聘客戶端

趙發(fā):58同城-汽車事業(yè)群

參考文獻

LLVM源碼:github/llvm/llvm-project

Clang/LLVM官方文檔:clang.llvm.org/docs/

蘋果WWDC 2013 Advances in Objective-C Module相關視頻:developer.apple/videos/play/wwdc2013/404/

蘋果WWDC 2018 Header Search Path相關視頻:developer.apple/videos/play/wwdc2018/415/

LLVM開發(fā)者大會Doug Gregor的視頻和PPT:llvm.org/devmtg/2012-11/

ftime-trace耗時報告配置:blog.csdn/wwchao2012/article/details/109147192

美團編譯速度優(yōu)化公眾號文章:mp.weixin.qq/s?__biz=MjM5NjQ5MTI5OA==&mid=2651760497&idx=1&sn=2042896ac13cbc9b010625c7c24897e8&chksm=bd127e3c8a65f72aab2f2e0993654593bfbe4c44db36709f909ae40ce69cb0c2e02598c0ebc0&cur_album_id=1751291735726456834&scene=189#rd

Hmap工具:github/milend/hmap

llvm-bcanalyzer:llvm.org/docs/CommandGuide/llvm-bcanalyzer.html

bitstream format:llvm.org/docs/BitCodeFormat.html

PCH結構:clang.llvm.org/docs/PCHInternals.html#pchinternals-modules

Modules:clang.llvm.org/docs/Modules.html

 
(文/企資小編)
免責聲明
本文僅代表作發(fā)布者:企資小編個人觀點,本站未對其內(nèi)容進行核實,請讀者僅做參考,如若文中涉及有違公德、觸犯法律的內(nèi)容,一經(jīng)發(fā)現(xiàn),立即刪除,需自行承擔相應責任。涉及到版權或其他問題,請及時聯(lián)系我們刪除處理郵件:weilaitui@qq.com。
 

Copyright ? 2016 - 2025 - 企資網(wǎng) 48903.COM All Rights Reserved 粵公網(wǎng)安備 44030702000589號

粵ICP備16078936號

微信

關注
微信

微信二維碼

WAP二維碼

客服

聯(lián)系
客服

聯(lián)系客服:

在線QQ: 303377504

客服電話: 020-82301567

E_mail郵箱: weilaitui@qq.com

微信公眾號: weishitui

客服001 客服002 客服003

工作時間:

周一至周五: 09:00 - 18:00

反饋

用戶
反饋

主站蜘蛛池模板: 广州九盈机械有限公司| 江苏三麦食品机械有限公司| 北京包装机械有限公司| 深圳机械院建筑设计有限公司| 机械有限公司 法兰| 杭州通产机械有限公司| 山东青州机械有限公司| 温州工程机械有限公司| 河北晓进机械制造有限公司| 珠海市中鑫隆机械化建设工程有限公司| 江苏佳力起重机械制造有限公司| 丽驰精密机械有限公司| 盐城市成功机械制造有限公司| 江苏恒械机械有限公司| 浙江瑞志机械有限公司| 玉环华邦机械有限公司| 杭州贝克机械有限公司| 福州 机械 有限公司| 艾珍机械设备制造有限公司| 合心机械制造有限公司| 河北洲际重工有限公司| 无锡建仪仪器机械有限公司| 沈阳工程机械有限公司| 上海福源机械有限公司| 广州机械自动化有限公司| 杭州龙云水利机械制造有限公司 | 深圳固尔琦包装机械有限公司| 山东永锋钢铁有限公司| 辽宁 机械制造有限公司| 永盛机械设备有限公司| 西得乐机械有限公司| 武汉吕工机械有限公司| 上海 精密机械有限公司| 山鑫机械制造有限公司| 温州市顺达服装机械有限公司| 常熟市机械有限公司| 东莞市柯达机械有限公司| 玻璃设备机械有限公司| 河北农哈哈机械有限公司| 诸城市中天机械有限公司| 青岛雷沃工程机械有限公司| 州东方机械有限公司| 德清章盟机械设备有限公司 | 上海嘉倍德塑胶机械有限公司| 巩义市瑞赛克机械设备有限公司| 新乡市中天机械有限公司| 莱州弘宇机械有限公司| 章丘宇龙机械有限公司| 上海昱庄机械有限公司| 鑫阳机械设备有限公司| 盐山宏润重工有限公司| 浙江欧森机械有限公司| 泰安展鸿木业机械有限公司| 河北澳森钢铁有限公司| 标准缝纫机菀坪机械有限公司| 工程机械配件有限公司| 广东明华机械有限公司| 苏州雁达机械有限公司| 安微博达重工有限公司| 江西钧天机械有限公司奔驰| 温州博宇机械有限公司| 烟台金元矿业机械有限公司| 郑州市机械有限公司| 宁波力劲机械有限公司| 苏州恩贝德机械有限公司| 农业发展有限公司起名| 上海展焱包装机械有限公司| 江苏金韦尔机械有限公司| 沈阳机械设备有限公司| 哈尔滨 机械 有限公司| 长兴诺力机械有限公司| 苏州德伊捷自动化机械有限公司| 上海中吉机械制造有限公司| 蓬莱禄昊化工机械有限公司| 肥城金塔机械有限公司| 长沙宏银机械有限公司| 上海陆达包装机械制造有限公司 | 湖南汇一制药机械有限公司| 安徽食品机械有限公司| 诸城盛新德机械有限公司| 创达机械制造有限公司| 瑞安市机械制造有限公司| 大理大钢钢铁有限公司| 科倍隆南京机械有限公司| 四川建筑机械有限公司| 青岛木工机械有限公司| 上海又高机械有限公司| 临海正大机械有限公司| 荏原机械淄博有限公司| 宁波兴波机械有限公司| 江苏金沃机械有限公司| 莆田 机械有限公司| 浙江嘉益机械有限公司| 重庆巨泰机械有限公司| 东莞协鑫机械有限公司| 浙江吉隆机械有限公司| 重庆瀚源机械有限公司| 永明机械制造有限公司| 天津海特传动机械有限公司| 劲源机械设备有限公司| 江苏沃元精密机械有限公司| 首钢伊犁钢铁有限公司| 烟台海州机械有限公司| 仙游东亚机械有限公司| 意达纺织机械有限公司| 旭田包装机械有限公司| 深圳格瑞克机械有限公司| 河南鼎科机械有限公司| 科尼起重机设备(上海)有限公司| 东营石油机械有限公司| 武汉市快诚机械有限公司| 唐山国丰钢铁有限公司| 山东起重机械有限公司| 江苏双箭输送机械有限公司| 深圳市稻田包装机械有限公司 | 湖南正中制药机械有限公司| 岳阳神冈起重电磁铁有限公司 | 上海恒麦食品机械有限公司| 山东 重工有限公司| 武汉餐至饮机械设备有限公司 | 济南大鹏机械设备有限公司| 天津 机械 有限公司| 上海钊凯包装机械有限公司| 济南华工液压机械有限公司 | 上海舜诺机械有限公司| 青岛一津机械有限公司| 珠海市广浩捷精密机械有限公司| 太原市 机械有限公司| 鸿达机械设备有限公司| 临沂华星机械有限公司| 天津钢管钢铁贸易有限公司| 海沃机械扬州有限公司| 海南建设工程机械施工有限公司| 烨隆精密机械有限公司| 鑫鑫建筑机械有限公司| 长沙盛泓机械有限公司| 青岛西城铸造机械有限公司| 嘉兴精密机械有限公司| 江苏中威重工机械有限公司| 江阴市洪腾机械有限公司| 郑州市机械设备有限公司| 常州拓美威精密机械有限公司| 浙江恒机械有限公司| 北京液压机械有限公司| 陕西鑫钢机械有限公司| 青岛液压机械有限公司| 浙江青山钢铁有限公司| 河南万合机械有限公司| 沈阳维用精密机械有限公司招聘| 韩通船舶重工有限公司| 浙江春江茶叶机械有限公司| 徐工机械有限公司现状| 济宁天鸿机械有限公司| 嘉兴机械制造有限公司| 宁波钢铁有限公司工作| 合肥机械设备有限公司| 浩博机械制造有限公司| 浙江路杰机械有限公司| 杭州德工机械有限公司| 山东英胜机械有限公司| 机械有限公司经营范围| 济南精美机械设备有限公司| 力迈机械设备有限公司| 品龙精工机械有限公司| 南京钢铁联合有限公司| 佛山玻璃机械有限公司| 杭州海纳机械有限公司| 财益机械工业有限公司| 京西重工上海有限公司| 新乡天丰机械有限公司| 中山机械制造有限公司| 江阴起重机械有限公司| 丽驰精密机械有限公司| 大连 重工有限公司| 云南昆鼎机械设备有限公司| 江苏竣业过程机械设备有限公司 | 浙江昌亨机械有限公司| 合肥起重机械有限公司| 湖北首开机械有限公司| 徐州迈特机械有限公司| 浙江安驰机械有限公司| 烟台浩阳机械有限公司| 上海二和机械有限公司| 昆山东新力特精密机械有限公司 | 台州瑞进机械有限公司| 星光传动机械有限公司| 上海明硕机械有限公司| 雄雄精密机械有限公司| 长沙众城机械有限公司| 宁波市海达塑料机械有限公司 | 昆山大风机械有限公司| 美卓造纸机械有限公司| 山西机械设备有限公司| 大连起重矿山机械有限公司| 江苏三麦食品机械有限公司| 潍坊广德机械有限公司| 河南星光机械有限公司| 华通动力重工有限公司| 油机机械工业有限公司| 荆州华力机械有限公司| 无锡新麦机械有限公司| 河北东方富达机械有限公司| 诸城市盛和机械有限公司| 烟台天成机械有限公司| 深圳华盛昌机械实业有限公司| 浙江精劲机械有限公司| 云南中拓钢铁有限公司| 扬州巨人机械有限公司| 闽源钢铁有限公司停产| 上海楷钛机械制造有限公司| 温岭宏业机械有限公司| 台州 机械有限公司| 雅康精密机械有限公司| 镇田机械平湖有限公司| 山东泗水泰峰面粉机械有限公司| 新乡矿山起重机有限公司| 华东油压机械制造有限公司 | 上海液压机械有限公司| 江苏卫东机械有限公司| 山东龙腾机械有限公司| 台进精密机械有限公司| 无锡建仪仪器机械有限公司| 德国机械制造有限公司| 上海善佳机械设备有限公司| 福建 机械有限公司| 东方机械制造有限公司| 郑州正科机械有限公司| 浙江吉隆机械有限公司| 厦门洪海机械有限公司| 青州泰达机械有限公司| 三一起重机械有限公司| 浙江炬达机械有限公司| 天津菲特机械有限公司| 日发纺织机械有限公司| 江苏佳粮机械有限公司| 杭州重型机械有限公司| 武安市文安钢铁有限公司| 玉环博行机械有限公司| 东莞市永乐机械有限公司| 东莞市正一轴承机械有限公司 | 常州浦发机械有限公司| 合肥春华起重机械有限公司| 江阴市科盛机械有限公司| 泉州市工程机械有限公司| 金纬机械常州有限公司| 华泰精密机械有限公司| 山东明沃机械有限公司| 宁波昌扬机械工业有限公司| 昆山乙盛机械工业有限公司| 上海隆康机械设备有限公司| 福建三嘉钢铁有限公司| 徐工随车起重机有限公司| 新湾机械有限公司招聘| 沃德精密机械有限公司| 重庆培柴机械制造有限公司| 国义特种钢铁有限公司| 机械有限公司 南丰| 南通力福通起重机械有限公司 | 江苏贝尔机械有限公司| 湘潭丰弘机械制造有限公司| 青州市国发包装机械有限公司| 中施机械设备有限公司| 江苏联顺机械有限公司| 安徽金丰机械有限公司| 天重江天重工有限公司| 东营石油机械有限公司| 美心翼申机械有限公司| 山东神力起重机械有限公司| 温州利波机械有限公司| 上海轶鹰起重机械有限公司| 山东泰安煤矿机械有限公司| 上海毅锴机械有限公司| 台州万洲机械有限公司| 科尼乐机械设备有限公司| 中科包装机械有限公司| 天津英德诺机械设备有限公司| 苏州荣业机械有限公司| 上海得力起重索具有限公司| 国浩机械制造有限公司| 浙江路杰机械有限公司| 上海 输送机械有限公司| 浙江恒齿传动机械有限公司| 中山冠力机械有限公司| 青岛永正化工机械有限公司| 佛山市机械设备有限公司| 上海铁杉机械有限公司| 辽宁机械制造有限公司| 泰田液压机械有限公司| 东莞市铖铭机械有限公司 | 潍坊山水环保机械制造有限公司| 金泰机械制造有限公司| 好烤克食品机械有限公司| 苏州 机械 有限公司| 连云港 机械有限公司| 无锡通用机械有限公司| 烟台宏兴机械有限公司| 焦作机械制造有限公司| 南通凯瑞德机械有限公司| 均强机械苏州有限公司| 天津市申成包装机械有限公司| 河北永洋钢铁有限公司详细地址| 青岛佳友包装机械有限公司| 天津亨旺机械有限公司| 上海机械制造有限公司| 上海凡贝机械有限公司| 东莞市东机械设备有限公司| 江苏佳成机械有限公司| 佛山市科振机械设备有限公司| 徐州机械设备有限公司| 陕西 机械有限公司怎么样| 上海机械工程有限公司| 小松山推工程机械有限公司| 珠海市机械有限公司| 志庆机械设备有限公司| 北京恒机械有限公司| 南京恒昌包装机械有限公司| 长沙晶锐机械有限公司| 中施机械设备有限公司| 青岛青锻锻压机械有限公司| 上海长江服装机械有限公司| 龙南福鑫钢铁有限公司| 江苏明珠试验机械有限公司| 东莞市乔锋机械有限公司| 宝德机械国际有限公司| 江苏海豚船舶机械有限公司| 宜兴永康机械有限公司| 常州杰洋精密机械有限公司 | 唐山港陆钢铁有限公司| 安庆市机械有限公司| 上海重工机械有限公司| 丰凯机械制造有限公司| 星精密机械有限公司| 佛山精诚机械有限公司| 无锡锡南机械有限公司| 宝德机械国际有限公司| 上海升立机械制造有限公司| 杭州沃沃机械有限公司| 宝钢湛江钢铁有限公司| 上海石化机械制造有限公司| 青岛诺恩包装机械有限公司| 沧州瑞创机械制造有限公司| 天津同力重工有限公司| 东阳市机械有限公司| 常州龙鑫化工机械有限公司| 郑州市鼎盛机械制造有限公司| 上海祎飞机械有限公司| 天津市华天世纪机械有限公司 | 浙江上石化机械有限公司| 杭州天杨机械有限公司| 中设(苏州)机械设备工程有限公司| 江阴市机械制造有限公司| 潍坊铭金机械有限公司| 广州汉达机械有限公司| 苏州晋日五金机械有限公司| 合肥机械制造有限公司| 浙江机械制造有限公司| 固尔琦包装机械有限公司| 村田机械上海有限公司| 重庆卡滨通用机械有限公司| 常州纺织机械有限公司| 淄博协丰机械有限公司| 常州胜代机械有限公司| 郴州粮油机械有限公司| 上海建筑机械有限公司| 宁波固奇包装机械制造有限公司 | 宁波博日机械有限公司| 成都欧曼机械有限公司| 上海凯机械有限公司| 郑州长城机械有限公司| 浙江华天机械有限公司| 人科机械陕西有限公司| 云南昆鼎机械设备有限公司| 常州腾睿机械有限公司| 宁波东力机械制造有限公司| 布勒常州机械有限公司| 翰林机械制造有限公司| 山东博杰重型工程机械有限公司 | 绍兴 机械 有限公司| 山东高机工业机械有限公司| 无锡力马化工机械有限公司| 成都工程机械有限公司| 石油机械制造有限公司| 上海香宝机械设备有限公司| 汶瑞机械山东有限公司| 徐州随车起重机有限公司| 南京竣业过程机械设备有限公司| 东莞市泽冠机械有限公司| 芜湖中安重工自动化装备有限公司 | 瑞安市方泰机械有限公司| 青岛云龙纺织机械有限公司| 苏州松博机械有限公司| 大连蓝德机械有限公司| 常州捷佳创精密机械有限公司| 江苏石油机械有限公司| 常州杰和机械有限公司| 山东港中钢铁有限公司| 昆山市升达机械制造有限公司| 河南天成矿山起重机有限公司 | 合肥至信机械有限公司| 大连机械制造有限公司| 山东吉恒机械有限公司| 浙江隆信机械制造有限公司| 中山市凌宇机械有限公司| 江苏洪流化工机械有限公司| 东莞市得士威机械工业有限公司 | 济南四通机械有限公司| 宁波市凯博数控机械有限公司| 老挝第一钢铁有限公司| 上海盾克机械有限公司| 路通重工机械有限公司| 包装机械设备有限公司| 深圳市神田机械设备有限公司| 洛阳中收机械装备有限公司招聘 | 东莞大兴发机械有限公司| 佳木斯佳联收获机械有限公司| 济南 升降机械有限公司| 扬州扬工机械有限公司| 永腾弹簧机械设备有限公司| 大方起重机械有限公司| 天津传动机械有限公司| 重庆屯茂机械有限公司| 东莞市益彩机械有限公司| 泰安市民乐机械制造有限公司| 贵州机械设备有限公司| 河北州科重工有限公司| 杭州双利机械有限公司| 杭州正驰达精密机械有限公司| 浙江坤鸿机械设备有限公司| 上海液压机械有限公司| 广州美特机械有限公司| 唐山印刷机械有限公司| 洛阳美卓重工机械有限公司| 山东讴神机械制造有限公司| 上海华预机械制造有限公司| 同鼎机械设备有限公司| 东风悦达起亚汽车有限公司| 上海德元机械设备有限公司| 青岛奥威机械有限公司| 佳友精密机械有限公司| 东莞精密机械有限公司| 岳阳神冈起重电磁铁有限公司 | 青州市晨光机械有限公司| 广西千里通机械设备有限公司| 山东瀚业机械有限公司| 河南真牛起重机有限公司| 北京盛美食品机械有限公司| 上海高敦精密机械有限公司| 上海戴服特包装机械有限公司| 临沂盖氏机械有限公司| 无锡市锡恒机械有限公司| 新麦机械有限公司官网| 福建信达机械有限公司| 唐山荣信钢铁有限公司| 南通佳吉机械有限公司| 力迈机械设备有限公司| 江苏拓威机械有限公司| 宁江精密机械有限公司| 北京液压机械有限公司| 沈阳友维机械有限公司| 山东通用机械有限公司| 上海拓稳机械有限公司| 广州闽欣机械设备有限公司| 瑞达机械设备有限公司| 烟台山一机械有限公司| 廊坊包装机械有限公司| 苏州柯瑞机械有限公司| 淄博晟峰机械有限公司| 上海德珂斯机械自动化技术有限公司| 盾建重工制造有限公司| 华宝机械制造有限公司| 青岛德利机械有限公司| 北京京民兴机械设备有限公司 | 东莞市机械制造有限公司| 宝力机械有限公司招聘| 山东临沂机械有限公司| 耐驰上海机械仪器有限公司| 张家口机械有限公司| 志庆机械设备有限公司| 平湖市机械有限公司| 东莞市嘉鲁特注塑机械有限公司| 济宁立派工程机械有限公司| 徐州东南钢铁工业有限公司| 浙江海蜜机械有限公司| 潍坊华星机械有限公司| 成都弘林机械有限公司| 华西钢铁有限公司电话| 沧州沧狮磨浆机械有限公司| 常州宝菱重工机械有限公司| 济宁矿山机械有限公司| 山东誉亚大豆机械制造有限公司 | 沈阳黎明机械有限公司| 杭州大禹机械有限公司| 山东泰安煤矿机械有限公司| 江阴机械制造有限公司怎么样| 苏州伟鼎机械设备有限公司| 宿迁百通机械有限公司| 安徽精密机械有限公司| 尤工机械设备有限公司| 陕西 机械有限公司怎么样| 卫华起重机有限公司| 苏州斗山工程机械有限公司 | 青岛 重工 有限公司| 浙江纺织机械有限公司| 淄博宏达钢铁有限公司| 潍坊凯信机械有限公司| 山东永峰钢铁有限公司| 海宁弘德机械有限公司| 上海精工机械有限公司| 诸城市华钢机械有限公司| 唐山市德龙钢铁有限公司| 昆山日晟机械有限公司| 金属制品有限公司起名| 安阳嘉和机械有限公司| 温州博大机械有限公司| 星塔机械深圳有限公司| 星光传动机械有限公司| 宁波思进机械有限公司| 江苏科圣化工机械有限公司| 承德建龙钢铁有限公司| 江苏力威机械有限公司| 豪德机械上海有限公司| 禹城市华普机械设备有限公司| 重庆墨龙机械有限公司| 长葛市机械有限公司| 郴州粮油机械有限公司| 佛山市机械设备有限公司| 江苏爱斯特机械有限公司怎么样| 旭恒精工机械制造有限公司| 江苏苏东化工机械有限公司| 仕诚塑料机械有限公司| 佛山市机械制造有限公司| 广西徐重机械有限公司| 矿山起重机有限公司| 云南旷迪机械有限公司| 上海固好包装机械有限公司| 杭州海兴机械有限公司| 西马特机械制造有限公司| 瑞安市瑞博机械有限公司| 勤美达精密机械有限公司| 威海华丰机械有限公司| 鸿达机械设备有限公司| 咸阳联合机械有限公司| 北京丰茂植保机械有限公司| 东莞市瑞辉机械制造有限公司| 机械租赁有限公司名字| 杭州丽伟电脑机械有限公司| 太行机械工业有限公司| 无锡市川中五金机械有限公司 | 恒泰机械制造有限公司| 温州机械制造有限公司| 潍坊坊通机械有限公司| 机械设备有限公司经营范围| 瑞安正博机械有限公司| 贝力特机械有限公司| 宜昌 机械有限公司| 武汉山推机械有限公司| 湖北天和机械有限公司| 济南新思路机械设备有限公司 | 华天机械制造有限公司| 江苏长强钢铁有限公司| 合肥光裕机械有限公司| 安徽机械制造有限公司| 宁波将军机械有限公司| 克朗斯机械有限公司| 重庆起重机厂有限公司| 武汉四方圆机械设备有限公司| 镇江机械设备有限公司| 北京明日之星玻璃机械有限公司 | 浙江万能弹簧机械有限公司| 浙江海荣机械有限公司| 山东天力液压机械有限公司| 湖北铁正机械有限公司| 扬州市机械制造有限公司| 上海昱音机械有限公司| 湖南长河机械有限公司| 苏州神峰起重机械有限公司| 苏州琦珏机械有限公司| 四川腾中重工机械有限公司| 临沂工程机械有限公司| 上海 精密机械制造有限公司| 重庆志成机械有限公司| 新马木工机械有限公司| 上海冬松精密机械有限公司| 常州龙鹏机械有限公司| 浙江建达机械有限公司| 凯伯精密机械有限公司| 常州市永明机械制造有限公司 | 张家港市亿利机械有限公司 | 昆山裕邦机械有限公司| 山东 钢铁有限公司| 济宁市兴旺机械制造有限公司| 恒兴机械设备有限公司| 河北液压机械有限公司| 佛山隆机械有限公司| 淮安机械制造有限公司| 博山 机械有限公司| 陕西机械设备有限公司| 温州光明印刷机械有限公司| 苏州 机械 有限公司| 苏州昶智精密机械有限公司| 诚泰精密机械有限公司| 恒源机械制造有限公司| 山推抚起机械有限公司| 江苏炬峰机械有限公司| 浙江炬达机械有限公司| 扬州金威机械有限公司| 东阳机械制造有限公司| 河南矿山起重机有限公司销售电话| 苏州松发机械有限公司| 张家港市港丰机械有限公司| 莱州华汽机械有限公司| 江苏华澄重工有限公司| 苏州昶智精密机械有限公司| 唐山盛财钢铁有限公司| 威海卓远机械有限公司| 江阴市药化机械有限公司| 济南 液压机械有限公司| 广州海缔机械有限公司| 佛山市顺德区金工铝门窗机械实业有限公司 | 扬州永瑞机械有限公司| 温州市日力轻工机械有限公司| 鸿江机械制造有限公司| 上海光华印刷机械有限公司| 金韦尔机械有限公司| 天津蓝科机械有限公司| 河南安普包装机械制造有限公司| 济宁五创机械有限公司| 厦门东亚机械有限公司| 台一精工机械有限公司| 曲阜圣达机械有限公司| 苏州信能精密机械有限公司| 江苏坤泰机械有限公司| 冶金机械制造有限公司| 河北神耕机械有限公司| 常州动力机械有限公司| 东阳机械设备制造有限公司| 山东山建机械有限公司| 苏州工业园区嘉宝精密机械有限公司 | 淄博翔鹏机械有限公司| 湖南龙凤机械制造有限公司| 上海新沪机械有限公司| 常州制药机械有限公司| 瑞安市机械制造有限公司| 广州市德晟机械有限公司| 上海博强机械有限公司| 台州欧玮机械有限公司| 上海环野机械有限公司| 广州市通风机械设备有限公司| 广州萱裕机械有限公司| 佛山市晶菱玻璃机械有限公司| 浙江卓驰机械有限公司| 佛山突破机械制造有限公司| 江苏久盛机械设备有限公司| 北京石油机械有限公司| 鹤壁市双信矿山机械有限公司| 上海德元机械设备有限公司| 集瑞联合重工有限公司| 东莞机械制造有限公司| 苏州福润机械有限公司| 天门仙粮机械有限公司| 成机械设备有限公司| 东莞宏彰机械有限公司| 苏州力强机械制造有限公司 | 保定市恒瑞游乐机械有限公司| 亨沃机械设备有限公司| 河北文丰钢铁有限公司| 苏州奥天诚机械有限公司| 上海昊农农业机械有限公司| 大京机械山东有限公司| 山东伊莱特重工有限公司| 三星重工业宁波有限公司招聘| 福建巨邦机械有限公司| 吴江精密机械有限公司| 上海凯奇机械设备有限公司| 郑州市建新机械制造有限公司| 潍坊凯信机械有限公司| 济南欧亚德数控机械有限公司| 青岛特固机械有限公司| 南京金顿重工机械有限公司| 青岛工程机械有限公司| 石家庄安瑞科气体机械有限公司 | 郑州市昌利机械制造有限公司 | 金沙机械制造有限公司| 鞍山重工机械有限公司| 北京道森起点信息技术有限公司| 佛山市创利宝包装机械有限公司| 沈阳 机械制造有限公司| 东莞志成机械有限公司| 沈阳水泥机械有限公司| 济宁经纬工程机械有限公司| 东莞豪力机械有限公司| 昆玉钢铁有限公司招聘| 广东森人机械有限公司| 浙江邦泰机械有限公司| 山东瑞浩重型机械有限公司| 北京起重设备有限公司| 青州市三联重工设备制造有限公司 | 贵州运东机械有限公司| 江苏巨能机械有限公司| 重庆中容石化机械制造有限公司| 安徽康乐机械有限公司| 新余钢铁厂有限公司| 河南省金特振动机械有限公司 | 漳州南方机械有限公司| 唐山荣信钢铁有限公司| 诺威起重设备苏州有限公司| 温州市友田包装机械有限公司 | 鑫泰数控机械有限公司| 莱州市龙骏化工机械有限公司 | 上海戈扬包装机械有限公司| 青岛宏达锻压机械有限公司| 广州九盈机械有限公司| 苏州锐豪机械制造有限公司| 柳州市机械有限公司| 豪德机械上海有限公司| 北京晨光兴业机械有限公司| 大连红日机械有限公司| 河南省机械有限公司| 绍兴联科机械有限公司| 太仓九本机械有限公司| 大连工进机械制造有限公司| 江苏竣业过程机械设备有限公司| 山东曲阜机械有限公司| 大连万阳重工有限公司| 湖北 钢铁有限公司| 山东利达工程机械有限公司| 广州卓远机械有限公司| 上海兴享机械工业有限公司| 河北常富机械有限公司| 工程机械设备有限公司| 广西玉柴重工有限公司| 上海起重设备有限公司| 南通赛孚机械设备有限公司| 泰上机械设备有限公司| 昆山六丰机械工业有限公司 | 深圳市 机械 有限公司| 镇江机械设备有限公司| 无锡市川中五金机械有限公司 | 上海又高机械有限公司| 江苏鑫锋重工机床有限公司| 浙江阜康机械有限公司| 沧州瑞创机械制造有限公司| 钦州力顺机械有限公司| 重庆庆泰机械有限公司| 台林机械有限公司 -| 湖北川谷机械有限公司| 信息技术有限公司起名| 佛山市鹏轩机械制造有限公司| 烟台精越达机械设备有限公司 | 杭州鸿立机械有限公司| 许昌智工机械制造有限公司| 章丘市机械有限公司| 苏州恒威海绵机械有限公司| 德阳思远重工有限公司| 上海太腾机械设备有限公司| 上海食品机械有限公司| 东营程祥机械有限公司| 斗山机械工程有限公司| 东莞市鼎祥通用机械设备有限公司 | 农业机械装备有限公司| 山西汉通机械有限公司| 佳木斯佳联收获机械有限公司| 上海国翔包装机械制造有限公司 | 焦作市虹起制动器有限公司| 烟台市利达木工机械有限公司 | 山东德丰重工有限公司| 浙江万龙机械有限公司| 首钢长白机械有限公司| 单县江华机械有限公司| 佛山精诚机械有限公司| 江阴市药化机械有限公司| 上海建冶重工机械有限公司| 上海理贝包装机械有限公司 | 河南柴油机重工有限公司| 无锡盛达机械制造有限公司| 昆山六丰机械工业有限公司| 广东龙辉基业建筑机械有限公司| 佛山(顺德)机械有限公司| 唐山津西钢铁有限公司| 东莞市恒生机械制造有限公司| 镇田机械平湖有限公司| 河南矿山重型起重机械有限公司 | 常州斯太尔动力机械有限公司| 哈尔滨纳诺机械设备有限公司| 昆山市机械制造有限公司| 宁波美亚特精密机械有限公司| 青岛鲁奥机械有限公司| 浙江伟焕机械制造有限公司| 源通机械设备有限公司| 隆英金坛机械有限公司| 南京明瑞机械设备有限公司| 上海华预机械制造有限公司| 河南江瀚机械制造有限公司| 东营程祥机械有限公司| 东莞市金拓机械有限公司| 国义特种钢铁有限公司| 安丘机械制造有限公司| 机械有限公司 机械手| 长春 机械 有限公司| 河南省矿山起重机制造有限公司| 上海映易包装机械设备有限公司| 安徽远鸿机械自动化有限公司| 永盛达机械有限公司| 洛阳隆中重工机械有限公司| 瑞安市创博机械有限公司| 北京包装机械有限公司| 河南 机械制造有限公司| 山东腾机械有限公司| 江阴市液压机械有限公司| 山西 重工有限公司| 苏州立注机械有限公司| 南京康尼精密机械有限公司| 成都神钢建设机械有限公司| 东莞启益电器机械有限公司 | 纽科伦起重机有限公司| 重工机械制造有限公司| 鑫达机械设备有限公司| 温州万润机械有限公司| 西安普阳机械有限公司| 华盛机械设备有限公司| 上海楷钛机械制造有限公司| 杭州 机械 有限公司| 湖南龙凤机械制造有限公司| 众力达机械有限公司| 鑫科木工机械有限公司| 济南森华精密机械有限公司| 上海 机械有限公司| 三技精密机械有限公司| 北京城建重工有限公司| 宁波机械设备有限公司| 苏州凯尔博精密机械有限公司| 宁波立强机械有限公司| 郑州锦德润机械设备有限公司 | 四川凌峰航空液压机械有限公司| 沧州昌鸿磨浆机械有限公司 | 四川青城机械有限公司| 杭州大禹机械有限公司| 山东凯达起重机械有限公司| 扬州恒润钢铁有限公司| 南通太和机械有限公司| 中山市凌宇机械有限公司| 洛阳钢峰机械有限公司| 上海众星洗涤机械制造有限公司| 百赞精密机械有限公司| 郑州机械制造有限公司| 大连矢岛机械有限公司| 上海起重设备有限公司| 湖州二轻机械有限公司| 无锡旭英机械有限公司| 克朗斯机械有限公司| 广州市旭朗机械设备有限公司| 贝纳特机械有限公司| 上海服装机械有限公司| 江苏中科机械有限公司| 承德 机械有限公司| 唐山凯恒钢铁有限公司| 和和机械(张家港)有限公司| 嘉诚机械制造有限公司| 苏州联佳精密机械有限公司| 深圳市硕方精密机械有限公司 | 三联传动机械有限公司| 秦皇岛宏兴钢铁有限公司| 上海欧特莱阀门机械有限公司| 湖北昌胜机械设备制造有限公司| 昆山尚亦精密机械有限公司| 杭州化工机械有限公司| 潍坊凯德塑料机械有限公司| 深圳精机械有限公司| 沈阳带锯机械有限公司| 山东山工机械有限公司| 沈阳顺达重矿机械制造有限公司 | 山东大力机械有限公司| 广东中泽重工有限公司| 东莞丰堡精密机械有限公司| 成都宏机械有限公司| 安阳亚新钢铁有限公司| 沧州瑞创机械制造有限公司| 北京永创通达机械设备有限公司 | 蓬莱巨涛海洋工程重工有限公司怎么样| 苏州仁成包装机械有限公司| 万杰食品机械有限公司| 东营石油机械有限公司| 山东力王重工机械有限公司| 南京一嘉起重机械制造有限公司| 安来动力机械有限公司| 青岛包装机械有限公司| 宁波传动机械有限公司| 苏州鸿安机械有限公司| 临沂三友重工有限公司| 中山冠力机械有限公司| 兰州 机械 有限公司| 上海纽荷兰农业机械有限公司 | 华东机械制造有限公司| 潍坊 机械 有限公司| 江西欧克机械有限公司| 泸州长江工程机械成套有限公司| 东营海河机械有限公司| 泰瑞机械有限公司待遇| 江苏三麦食品机械有限公司| 广州赛威机械有限公司| 贝纳特机械有限公司| 上海宝锻机械制造有限公司| 昆山崇粲机械有限公司| 广东华三行工程机械有限公司 | 华新机械有限公司官网| 景德镇 机械有限公司| 南京登峰起重设备制造有限公司| 厦门 机械有限公司| 宁波迈拓斯数控机械有限公司 | 郑州工程机械有限公司| 浙江豪盛印刷机械有限公司 | 东莞麒麟机械有限公司| 黄石华旦机械制造有限公司| 徐州博丰钢铁有限公司| 快克数控机械有限公司| 咸阳机械制造有限公司| 广州日富机械有限公司| 山东永华机械有限公司| 江苏鑫锋重工机床有限公司| 华通动力重工有限公司| 浙江嘉元机械制造有限公司 | 安徽格瑞德机械制造有限公司 | 无锡真木机械有限公司| 天津中核机械有限公司| 南通凯瑞德机械有限公司| 山东创铭机械有限公司| 天重江天重工有限公司| 昆山大风机械有限公司| 江苏船谷重工有限公司| 首钢长治钢铁有限公司| 唐山东方钢铁有限公司| 长沙三一重工有限公司| 无锡腾力机械有限公司| 宏兴钢铁有限公司官网| 盐城市联鑫钢铁有限公司| 佳友精密机械有限公司| 武汉联明机械有限公司| 南通虹波机械有限公司| 济南明美机械有限公司| 重庆嘉木机械有限公司| 新乡市金原起重机械有限公司| 南通福斯特机械制造有限公司| 蓬莱巨涛海洋工程重工有限公司怎么样 | 济南真诺机械有限公司| 济南金胜星机械设备有限公司| 长春合心机械制造有限公司 | 无锡永兴机械制造有限公司| 山东六丰机械有限公司| 联征机械设备有限公司| 临沂盖氏机械有限公司| 福建海源机械有限公司| 河北太行机械工业有限公司| 深圳机械设备有限公司| 嘉厨食品机械有限公司| 广东穗华机械设备有限公司| 昆成机械昆山有限公司| 宁波博纳机械有限公司| 沈阳机械制造有限公司| 成都弘邦机械有限公司| 机械电子制造有限公司| 广州市 机械有限公司| 青州市晨光机械有限公司| 杭州雅顿过滤机械有限公司 | 新劲力机械有限公司| 上海金纬机械有限公司| 天津机械配件有限公司| 无锡市阳通机械设备有限公司 | 宁波市鸿博机械制造有限公司 | 西安筑路机械有限公司| 杭州通绿机械有限公司| 佛山市洛德机械设备有限公司| 中核机械工程有限公司| 乐清市锐成机械有限公司| 江西四通重工机械有限公司 | 浙江恒通机械有限公司| 郑州茂祥机械有限公司| 临清市机械有限公司| 西安北村精密机械有限公司| 佛山市松川机械设备有限公司| 江阴市机械有限公司| 西安鸿运机械有限公司| 广州文穗塑料机械有限公司| 国机重工洛阳有限公司| 江苏天泽精工机械有限公司| 无锡金比机械有限公司| 无锡力恩机械有限公司| 旭恒精工机械制造有限公司| 新乡市利尔机械有限公司| 佐竹机械苏州有限公司| 南昌中昊机械有限公司| 河北文丰钢铁有限公司| 浙江传动机械有限公司| 厦门市机械有限公司| 迪砂常州机械有限公司| 邢台机械制造有限公司| 上海豪德机械有限公司| 重庆泰诺机械有限公司| 江苏双友重型机械有限公司| 常州铭盈包装机械有限公司|