模組化工作中,會指定庫與庫之間的依賴關係,根據依賴關係分層,但隨著開發進行,依賴關係又慢慢被破壞。如何讓後續的開發者能夠不破壞關係?目前有兩種常用手段:
- 不暴露標頭檔案,對於不同的庫開發者,其他庫以靜態庫方式。這種方式開發不夠方便,容易反覆造輪子,對業務分離很清晰的工程可以,但業務相關性較強的就沒法這麼做了。
- 嚴格的review機制。耗時耗力。
這兩種實施起來都挺不方便,我們的目的是想讓沒有依賴關係的引用直接import不到標頭檔案,從而提示開發者這個引用非法。
從import入手,先看下import:
import有兩種形式,<>和"",他們的區別:
stackoverflow上回答較高的解釋
the quoted form is for "local" includes of files (you need to specify the relative path from the current file, e.g. #include "headers/my_header.h"), while the angle-bracket form is for "global" includes -- those found somewhere on the include path passed to the compiler。
意思就是雙引號是用於本地的標頭檔案,需要指定相對路徑,尖括號是全域性的引用,其路徑由編譯器提供,如引用系統的庫。但在實際工程裡,不僅不用指定相對路徑,而且用<>也是能引用到的。事出有因,繼續看。xcode有個
use header map
的開關,這個開關的介紹:Enable the use of Header Maps, which provide the compiler with a mapping from textual header names to their locations, bypassing the normal compiler header search path mechanisms. This allows source code to include headers from various locations in the file system without needing to update the header search path build settings。
意思是開啟這個開關後,在本地會根據當前目錄生成一份檔名和相對路徑的對映,依靠這個對映,我們可以直接import工程裡的檔案,不需要依靠header search path。第一點中的問題得到解決,那就直接關閉這個開關吧。如果關閉
use header map
那麼就涉及到xcode build settings
中的header search path 和 user header search path
了。Header Search Paths:This is a list of paths to folders to be searched by the compiler for included or imported header files when compiling C, Objective-C, C++, or Objective-C++. Paths are delimited by whitespace, so any paths with spaces in them need to be properly quoted.
User Header Search Paths (USER_HEADER_SEARCH_PATHS)
This is a list of paths to folders to be searched by the compiler for included or imported user header files (those headers listed in quotes) when compiling C, Objective-C, C++, or Objective-C++. Paths are delimited by whitespace, so any paths with spaces in them need to be properly quoted. See Always Search User Paths (ALWAYS_SEARCH_USER_PATHS) for more details on how this setting is used. If the compiler doesn't support the concept of user headers, then the search paths are prepended to the any existing header search paths defined in Header Search Paths (HEADER_SEARCH_PATHS).
兩者都是提供search path的,區別在於一個指明是使用者的。並且提到如果編譯器不支援user headers概念,會從header search paths中去尋找。
- Always Search User Paths (ALWAYS_SEARCH_USER_PATHS)
If enabled, both#include-style and#include "header.h" -style directives search the paths in User Header Search Paths (USER_HEADER_SEARCH_PATHS) before Header Search Paths (HEADER_SEARCH_PATHS).
As a consequence, user headers, such as your ownString.h header, have precedence over system headers when using#include. This is done using the-iquote flag for the paths provided inUser Header Search Paths. If disabled and your compiler fully supports separate user paths, user headers are only accessible with#include "header.h" -style preprocessor directives.
在這裡我們可以看到,如果開啟了Always Search User Paths
,<>
和""
都可以引用到,如果關閉了,user headers
只能通過""
引用。
通過這一系列,我們的方案出來了,關閉use header map
,關閉Always Search User Paths
,通過ruby的xcodeproj 來修改工程檔案,根據設定好的依賴關係指定header search path或user header search paths。這樣,當不在header search path目錄下的檔案被import時,編譯器是會找不到的。