pub struct SdkSearch { /* private fields */ }Expand description
Search parameters for locating an Apple SDK.
This type can be used to construct a search for an Apple SDK given user chosen search parameters.
The search algorithm is essentially:
- Iterate through each registered search location.
- Discover candidate SDKs and filter.
- Globally sort (if enabled).
Search Locations
Search mechanisms / locations are represented via SdkSearchLocation and internally the searcher maintains a vector of locations. The default search locations are:
- Use path specified by
SDKROOTenvironment variable, if defined. - Find SDKs within the Developer Directory defined by the
DEVELOPER_DIRenvironment variable. - Find SDKs within the system installed
Xcodeapplication. - Find SDKs within the system installed Xcode Command Line Tools.
Simply call Self::location() to register a new location. If the default locations are not desirable, construct an empty instance via Self::empty() and register your explicit list of locations.
An attempt is made to only search a given location at most once. This is done in order to avoid redundant work. If a location is specified multiple times - even via different SdkSearchLocation variants - subsequent searches of that location will yield no distinct results. Duplicate SDKs can occur in the returned list.
Filtering
Filters can be registered to control which SDKs are emitted from the search.
By default, no filtering is performed. This means all SDKs in all search locations are returned. This can return SDKs belonging to multiple platforms (e.g. macOS and iOS).
The following functions control filtering:
If you are looking for an SDK to use (e.g. for compilation), you should at least use a platform filter. Otherwise you may see SDKs for platforms you aren’t targeting! It is also an encouraged practice to specify a minimum or maximum SDK version to use.
If you know you are targeting a specific OS version, applying a targeting filter via Self::deployment_target() is recommended. However, this filter is not always reliable. See the caveats in its documentation.
Sorting
By default, the returned list of SDKs is the chained result of SDKs discovered in all registered search locations. The order of the SDK within each search location is likely the sorted order of directory names as they appear on the filesystem.
If using an SDK for compilation, sorting by the SDK version is likely desired. Using the latest/newest SDK that supports a given deployment target is generally a best practice.
Implementations§
source§impl SdkSearch
impl SdkSearch
sourcepub fn empty() -> Self
pub fn empty() -> Self
Obtain an instance with an empty set of search locations.
The search will not resolve any SDKs unless a search location is registered with the instance.
sourcepub fn progress_callback(self, callback: SdkProgressCallback) -> Self
pub fn progress_callback(self, callback: SdkProgressCallback) -> Self
Define a function that will be called to provide updates on SDK search status.
sourcepub fn location(self, location: SdkSearchLocation) -> Self
pub fn location(self, location: SdkSearchLocation) -> Self
Add a location to search.
The location will be appended to the current search location list.
sourcepub fn platform(self, platform: Platform) -> Self
pub fn platform(self, platform: Platform) -> Self
Set the SDK platform to search for.
If you do not call this, SDKs for all platforms are returned.
If you are looking for a specific SDK to use, you probably want to call this. If you are searching for all available SDKs, you probably don’t want to call this.
sourcepub fn minimum_version(self, version: impl Into<SdkVersion>) -> Self
pub fn minimum_version(self, version: impl Into<SdkVersion>) -> Self
Minimum SDK version to require.
Effectively imposes a >= filter on found SDKs.
If using SimpleSdk and the SDK version could not be determined from
the filesystem path, the version is assumed to be 0.0 and this filter
will likely exclude the SDK.
sourcepub fn maximum_version(self, version: impl Into<SdkVersion>) -> Self
pub fn maximum_version(self, version: impl Into<SdkVersion>) -> Self
Maximum SDK version to return.
Effectively imposes a <= filter on found SDKs.
sourcepub fn deployment_target(
self,
target: impl ToString,
version: impl Into<SdkVersion>
) -> Self
pub fn deployment_target(
self,
target: impl ToString,
version: impl Into<SdkVersion>
) -> Self
Deployment target that the SDK must support.
When set, only SDKs that support targeting the given target-version pair will
be returned. Example values are (macosx, 10.15).
Only modern SDKs with SDKSettings.json files advertise their targeting settings
in a way that allows this filter to work.
Attempting to use this filter on SimpleSdk will result in a run-time
error at search time since these SDKs do not parse SDKSettings files.
sourcepub fn sorting(self, sorting: SdkSorting) -> Self
pub fn sorting(self, sorting: SdkSorting) -> Self
Define the sorting order for returned SDKs.
Default is SdkSorting::None.
sourcepub fn search<SDK: AppleSdk>(&self) -> Result<Vec<SDK>, Error>
pub fn search<SDK: AppleSdk>(&self) -> Result<Vec<SDK>, Error>
Perform a search, yielding found SDKs sorted by the search’s preferences.
May return an empty vector.
sourcepub fn filter_sdk<SDK: AppleSdk>(&self, sdk: &SDK) -> Result<bool, Error>
pub fn filter_sdk<SDK: AppleSdk>(&self, sdk: &SDK) -> Result<bool, Error>
Whether an SDK matches our search filter.
This is exposed as a convenience method to allow custom implementations of SDK searching using the filtering logic on this type.
Examples found in repository?
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
pub fn search<SDK: AppleSdk>(&self) -> Result<Vec<SDK>, Error> {
let mut sdks = vec![];
// Track searched locations to avoid redundant work.
let mut searched_platform_dirs = HashSet::new();
let mut searched_sdks_dirs = HashSet::new();
for location in &self.locations {
if let Some(cb) = &self.progress_callback {
cb(SdkSearchEvent::SearchingLocation(location.clone()));
}
// Expand each location to SDKs.
let resolved = location.resolve_location()?;
let candidate_sdks = match &resolved {
SdkSearchResolvedLocation::None => {
vec![]
}
SdkSearchResolvedLocation::PlatformDirectories(dirs) => dirs
.iter()
// Apply platform filter.
.filter(|dir| {
if let Some(wanted_platform) = &self.platform {
if &dir.platform == wanted_platform {
if let Some(cb) = &self.progress_callback {
cb(SdkSearchEvent::PlatformDirectoryInclude(dir.path.clone()));
}
true
} else {
if let Some(cb) = &self.progress_callback {
cb(SdkSearchEvent::PlatformDirectoryExclude(dir.path.clone()));
}
false
}
} else {
if let Some(cb) = &self.progress_callback {
cb(SdkSearchEvent::PlatformDirectoryInclude(dir.path.clone()));
}
true
}
})
// Apply duplicate search filter.
.filter(|dir| {
if searched_platform_dirs.contains(dir.path()) {
false
} else {
searched_platform_dirs.insert(dir.path().to_path_buf());
true
}
})
.map(|dir| dir.find_sdks::<SDK>())
.collect::<Result<Vec<_>, Error>>()?
.into_iter()
.flatten()
.collect::<Vec<_>>(),
SdkSearchResolvedLocation::SdksDirectory(path) => {
if searched_sdks_dirs.contains(path) {
vec![]
} else {
searched_sdks_dirs.insert(path.clone());
SDK::find_in_directory(path)?
}
}
SdkSearchResolvedLocation::SdkDirectory(path)
| SdkSearchResolvedLocation::SdkDirectoryUnfiltered(path) => {
vec![SDK::from_directory(path)?]
}
};
let mut added_count = 0;
for sdk in candidate_sdks {
let include = if resolved.apply_sdk_filter() {
self.filter_sdk(&sdk)?
} else {
if let Some(cb) = &self.progress_callback {
cb(SdkSearchEvent::SdkFilterSkip(sdk.sdk_path()));
}
true
};
if include {
sdks.push(sdk);
added_count += 1;
}
}
if location.is_terminal() && added_count > 0 {
break;
}
}
// Sorting should be stable with None variant. But we can avoid the
// overhead.
if self.sorting != SdkSorting::None {
sdks.sort_by(|a, b| self.sorting.compare_version(a.version(), b.version()))
}
Ok(sdks)
}