Compiler

RSS for tag

Discuss the various compiler and toolchain technologies used in development.

Posts under Compiler tag

54 Posts

Post

Replies

Boosts

Views

Activity

Xcode 16 Build & Archive Error - SPM
Since upgrading from Xcode 15 to 16, we have been experiencing a build error during compilation. Building on Xcode 15 still works with no issues. The error happens only on the first build after a clean. Subsequent builds succeed. This is an issue because our CI process archives the project from a clean slate, and this causes it to fail every time. I will attempt to describe the issue and include information I believe is relevant in this document. The error occurs on this import line within an Objective-C file during the Scan Dependencies step of compiling. This line imports our custom Objective-C to Swift bridging header file - "Swift2Objc.h". Our custom Objective-C to Swift bridging header file is simply wrapping the project’s auto-generated Objective-C to Swift bridging header file - "KWISwift.h". The error is specific to the import of the OfflineServices Swift Package. Specifically, the OfflineServices-Swift.h file - the Swift Package’s auto-generated Objective-C to Swift bridging file. Module JRE not found - the exact error (Also included as text on the bottom of the post) JRE is a third-party library provided to us as an xcframework. It is placed directly into our Swift Package as a binary target. The xcframework itself is composed of .a file and a Headers folder which includes header files and a module.modulemap. The module.modulemap file looks like this.
0
0
179
Mar ’25
XCode suddenly spending minutes running CLangStatCache
I've been using XCode for development in C++ for several years. Suddenly, today it started having the following problem: Any time I try to compile my code, (even if I just finished successfully compiling it), it spends several minutes running CLangStatCache. This is according to the result of "Perform Action... Build with Timing Summary". Furthermore, if I first delete the ".../DerivedData/SDKStatCaches.noindex" folder, the problem goes away and it compiles immediately. However, it creates a new folder with a 32 Mb file in it, and then has the same problem the next time unless I delete that folder again. I do not want to have to delete this file every time I compile my code. Is there some way to turn this off? What happened that is different today from any other day in the last several years? I did just download and install the latest System software update, including XCode... Did that break something?
1
0
65
Mar ’25
Reproducible Builds on iOS
Dear Apple Developer Forum! I'm in need of help regarding an issue that has to do with binaries. I'm building an iOS App that needs a fingerprint of its binaries, exclusively based on the source code written. A "reproducible" build, meaning that when I compile it on my machine and run checksum on it, the output (hash) will be the same, as if another device clones the project, compiles and checksums the values. The App depends on swift packages which depends on Swift Packages, which I've managed to compile to .o files, convert to .a files (static frameworks) and create xcframeworks, which the App depends on. They work great, once compiled, their checksum value does not change when App is compiled (unless source code of them is changed of course), but the Apps executable (checksummed inside the IPA) changes every time it's compiled. I'm guessing that perhaps the Xcode compiler injects a timestamp or other unique identifier in the binaries? Is there any way to have "reproducible" builds on iOS (Swift Xcode)? All input is greatly appreciated, Thank you very much, Kind regards Johan.
10
0
876
Mar ’25
Add static c library to xcode/swift
Hi, I want to build an ios app that uses static c libraries. For reference, i did the following as a test: Compiled a simple c date and time program with clang -c -arch arm64 -sysroot <iPhoneOSSDK_path> date.c -o date_arm64.o Created the static lib ar rcs libdatetime_arm64.a date_arm64.o Added the lib in my Xcode project. Added the (.a) file in Build Rules -> Link Binary With Libraries Included the (.a) and (.h) file path in Build Settings -> Search Paths -> Header and Library Search Path Created a Bridging-Header.h file where I added #import "date.h" In my App.swift file, I called the function for getting the date and time let dateTimeStr = String(cString: get_current_datetime()) print("Current Date and Time: \(dateTimeStr)") After doing all the steps above, I am met with the error - Cannot find 'get_current_datetime' in scope Is there any other method to use static c libraries in xcode?
1
1
322
Mar ’25
Issue with Module Import and Archiving a Mixed Swift/C Library Using Swift Package Manager
Hello everyone, I’m encountering an issue when trying to build and archive my library BleeckerCodesLib using Swift Package Manager. My project is structured with two targets: CBleeckerLib: A C target that contains my image processing code (C source files and public headers). BleeckerCodesLib: A Swift target that depends on CBleeckerLib and performs an import CBleeckerLib. Below is the relevant portion of my Package.swift: // swift-tools-version:5.7 import PackageDescription let package = Package( name: "BleeckerCodesLib", platforms: [.iOS(.v16)], products: [ .library(name: "BleeckerCodesLib", targets: ["BleeckerCodesLib"]) ], targets: [ .target( name: "CBleeckerLib", publicHeadersPath: "include" ), .target( name: "BleeckerCodesLib", dependencies: ["CBleeckerLib"] ) ] ) Directory Structure My project directory looks like this: BleeckerCodesLib/ ├── BleeckerCodesLib.xcodeproj/ │ └── xcuserdata/ │ └── robertopitarch.xcuserdatad/ │ └── xcschemes/ │ └── xcschememanagement.plist ├── BleeckerCodesLib.h ├── Package.swift └── Sources/ ├── CBleeckerLib/ │ ├── bleecker-lib.c │ └── include/ │ ├── bleecker-lib.h │ └── CBleeckerLib.h └── BleeckerCodesLib/ ├── UIImage+Extensions.swift ├── ImageProcessingUtility.swift ├── APIManager.swift ├── BleeckerCodesLib.swift ├── CameraView.swift ├── RealTimeCameraView.swift └── BleeckerCameraWrapper.swift Code Example In my Swift code (for example, in BleeckerCodesLib.swift), I import the C module as follows: import SwiftUI import UIKit import CBleeckerLib // Import the C module public struct BleeckerCodes { public struct DetectedCode { public let code: String public let corners: [CGPoint] public init(code: String, corners: [CGPoint]) { self.code = code self.corners = corners } } // Initialization function public static func initializeLibrary() -> String { bleecker_init() // Call the C module function return "BleeckerCodesLibrary initialized!" } // ... other functions } The Problem When I try to compile or archive the project using commands such as: xcodebuild archive -project BleeckerCodesLib.xcodeproj -scheme BleeckerCodesLib -destination "generic/platform=iOS" -archivePath "archives/BleeckerCodesLib" I receive the error: "no such module 'CBleeckerLib'" Any assistance or step-by-step guidance on resolving this integration issue would be greatly appreciated. Thank you in advance!
0
0
238
Feb ’25
The SwiftUI project will compile normally in xcode15.4, but will not compile in xcode16.2. The log is as follows:
SwiftCompile normal arm64 Compiling\ Checkmark.swift,\ SimpleClockView.swift,\ Constants.swift,\ CountDayHomeView.swift,\ ................ logs.txt eekfnzfsodwhcebuwavalipzmswp/Build/Intermediates.noindex/FocusPomoTimer.build/Debug-iphonesimulator/FocusPomoTimer.build/DerivedSources/IntentDefinitionGenerated/AppRunningIntents/AppRunningIntentIntent.swift /Users/wangzhenghong/Library/Developer/Xcode/DerivedData/FocusPomoTimer-eekfnzfsodwhcebuwavalipzmswp/Build/Intermediates.noindex/FocusPomoTimer.build/Debug-iphonesimulator/FocusPomoTimer.build/DerivedSources/IntentDefinitionGenerated/AppRunningIntents/AppStopIntentIntent.swift /Users/wangzhenghong/Library/Developer/Xcode/DerivedData/FocusPomoTimer-eekfnzfsodwhcebuwavalipzmswp/Build/Intermediates.noindex/FocusPomoTimer.build/Debug-iphonesimulator/FocusPomoTimer.build/DerivedSources/GeneratedAssetSymbols.swift While evaluating request TypeCheckSourceFileRequest(source_file "/Users/wangzhenghong/MyApp/NewPomoProject/FocusPomoTimer/FocusPomoTimer/Views/TimerViews/SimpleClockView.swift") While evaluating request TypeCheckFunctionBodyRequest(FocusPomoTimer.(file).SimpleClockView._@/Users/wangzhenghong/MyApp/NewPomoProject/FocusPomoTimer/FocusPomoTimer/Views/TimerViews/SimpleClockView.swift:27:25) While evaluating request PreCheckResultBuilderRequest(FocusPomoTimer.(file).SimpleClockView._@/Users/wangzhenghong/MyApp/NewPomoProject/FocusPomoTimer/FocusPomoTimer/Views/TimerViews/SimpleClockView.swift:27:25) Stack dump without symbol names (ensure you have llvm-symbolizer in your PATH or set the environment var LLVM_SYMBOLIZER_PATH to point to it): 0 swift-frontend 0x0000000107ab2a9c llvm::sys::PrintStackTrace(llvm::raw_ostream&amp;, int) + 56 1 swift-frontend 0x0000000107ab0cf0 llvm::sys::RunSignalHandlers() + 112 2 swift-frontend 0x0000000107ab3068 SignalHandler(int) + 292 3 libsystem_platform.dylib 0x000000019ee86de4 _sigtramp + 56 4 swift-frontend 0x0000000103d03758 swift::DiagnosticEngine::formatDiagnosticText(llvm::raw_ostream&amp;, llvm::StringRef, llvm::ArrayRefswift::DiagnosticArgument, swift::DiagnosticFormatOptions) + 432 5 swift-frontend 0x0000000103d042ac swift::DiagnosticEngine::formatDiagnosticText(llvm::raw_ostream&amp;, llvm::StringRef, llvm::ArrayRefswift::DiagnosticArgument, swift::DiagnosticFormatOptions) + 3332 6 swift-frontend 0x00000001028148d0 swift::AccumulatingFileDiagnosticConsumer::addDiagnostic(swift::SourceManager&amp;, swift::DiagnosticInfo const&amp;) + 944 7 swift-frontend 0x00000001028144e8 swift::AccumulatingFileDiagnosticConsumer::handleDiagnostic(swift::SourceManager&amp;, swift::DiagnosticInfo const&amp;) + 32 8 swift-frontend 0x0000000103d06960 swift::DiagnosticEngine::emitDiagnostic(swift::Diagnostic const&amp;) + 4276 9 swift-frontend 0x0000000102db4b10 swift::DiagnosticTransaction::~DiagnosticTransaction() + 184 10 swift-frontend 0x000000010350fbf0 (anonymous namespace)::PreCheckResultBuilderApplication::walkToExprPre(swift::Expr*) + 720 11 swift-frontend 0x0000000103bb9dac (anonymous namespace)::Traversal::visit(swift::Stmt*) + 2748 12 swift-frontend 0x00000001035093c8 swift::PreCheckResultBuilderRequest::evaluate(swift::Evaluator&amp;, swift::PreCheckResultBuilderDescriptor) const + 188 13 swift-frontend 0x00000001038bf294 swift::SimpleRequest&lt;swift::PreCheckResultBuilderRequest, swift::ResultBuilderBodyPreCheck (swift::PreCheckResultBuilderDescriptor), (swift::RequestFlags)2&gt;::evaluateRequest(swift::PreCheckResultBuilderRequest const&amp;, swift::Evaluator&amp;) + 36 14 swift-frontend 0x0000000103510568 swift::PreCheckResultBuilderRequest::OutputType swift::Evaluator::getResultCached&lt;swift::PreCheckResultBuilderRequest, swift::PreCheckResultBuilderRequest::OutputType swift::evaluateOrDefaultswift::PreCheckResultBuilderRequest(swift::Evaluator&amp;, swift::PreCheckResultBuilderRequest, swift::PreCheckResultBuilderRequest::OutputType)::'lambda'(), (void*)0&gt;(swift::PreCheckResultBuilderRequest const&amp;, swift::PreCheckResultBuilderRequest::OutputType swift::evaluateOrDefaultswift::PreCheckResultBuilderRequest(swift::Evaluator&amp;, swift::PreCheckResultBuilderRequest, swift::PreCheckResultBuilderRequest::OutputType)::'lambda'()) + 1256 15 swift-frontend 0x00000001035071f0 swift::TypeChecker::applyResultBuilderBodyTransform(swift::FuncDecl*, swift::Type) + 216 16 swift-frontend 0x00000001038c4d14 swift::TypeCheckFunctionBodyRequest::evaluate(swift::Evaluator&amp;, swift::AbstractFunctionDecl*) const + 484 17 swift-frontend 0x0000000103cd5e80 swift::TypeCheckFunctionBodyRequest::OutputType swift::Evaluator::getResultUncached&lt;swift::TypeCheckFunctionBodyRequest, swift::TypeCheckFunctionBodyRequest::OutputType swift::evaluateOrDefaultswift::TypeCheckFunctionBodyRequest(swift::Evaluator&amp;, swift::TypeCheckFunctionBodyRequest, swift::TypeCheckFunctionBodyRequest::OutputType)::'lambda'()&gt;(swift::TypeCheckFunctionBodyRequest const&amp;, swift::TypeCheckFunctionBodyRequest::OutputType swift::evaluateOrDefaultswift::TypeCheckFunctionBodyRequest(swift::Evaluator&amp;, swift::TypeCheckFunctionBodyRequest, swift::TypeCheckFunctionBodyRequest::OutputType)::'lambda'()) + 636 18 swift-frontend 0x0000000103c449f0 swift::AbstractFunctionDecl::getTypecheckedBody() const + 160 19 swift-frontend 0x00000001039130ec swift::TypeCheckSourceFileRequest::evaluate(swift::Evaluator&amp;, swift::SourceFile*) const + 868 20 swift-frontend 0x000000010391a680 swift::TypeCheckSourceFileRequest::OutputType swift::Evaluator::getResultUncached&lt;swift::TypeCheckSourceFileRequest, swift::TypeCheckSourceFileRequest::OutputType swift::evaluateOrDefaultswift::TypeCheckSourceFileRequest(swift::Evaluator&amp;, swift::TypeCheckSourceFileRequest, swift::TypeCheckSourceFileRequest::OutputType)::'lambda'()&gt;(swift::TypeCheckSourceFileRequest const&amp;, swift::TypeCheckSourceFileRequest::OutputType swift::evaluateOrDefaultswift::TypeCheckSourceFileRequest(swift::Evaluator&amp;, swift::TypeCheckSourceFileRequest, swift::TypeCheckSourceFileRequest::OutputType)::'lambda'()) + 620 21 swift-frontend 0x0000000103912d6c swift::performTypeChecking(swift::SourceFile&amp;) + 328 22 swift-frontend 0x000000010282fe00 swift::CompilerInstance::performSema() + 260 23 swift-frontend 0x000000010245cdf0 performCompile(swift::CompilerInstance&amp;, int&amp;, swift::FrontendObserver*) + 1532 24 swift-frontend 0x000000010245bbb4 swift::performFrontend(llvm::ArrayRef&lt;char const*&gt;, char const*, void*, swift::FrontendObserver*) + 3572 25 swift-frontend 0x00000001023e2a5c swift::mainEntry(int, char const**) + 3680 26 dyld 0x000000019ead0274 start + 2840 Command SwiftCompile failed with a nonzero exit code
0
0
321
Feb ’25
How to exclude header files from 3rd party pods from getting the Apple Clang warning policies?
I have the 'warnings as errors' policy set to Yes for Apple Clang and Swift compiler. As far as I know, there is no way to make exceptions to the warning policies from Swift compiler (correct me if I am wrong), what about Clang warning policies, specifically when it comes to header files from 3rd party pods? They don't show up on the Compile Sources so I can't apply flags such as -Wno-error=deprecated to them. Adding #pragma GCC... to them won't help as a fresh pod install will wipe the #pragma statements out. Is there a way to exclude the header files from pods from getting the warning policies from Clang so I won't see errors from them when compiling Clang modules that's a part of the build process?
0
0
300
Feb ’25
Does CLANG_CXX_LANGUAGE_STANDARD affect my Swift app and why is it not set to Compiler Default?
I was just comparing the build settings of two of my apps to try to understand why they behave differently (one of them uses the full screen on iPad, and the other one has small top and bottom black borders, although that's not the issue I want to discuss now). I saw that the option CLANG_CXX_LANGUAGE_STANDARD is set to gnu++0x for the older project, while it's set to gnu++17 for the newer one. The documentation lists different possible values and also a default one: Compiler Default: Tells the compiler to use its default C++ language dialect. This is normally the best choice unless you have specific needs. (Currently equivalent to GNU++98.) If it really is the best choice (normally), why is it not used when creating a new default Xcode project? Or is it better to select a newer compiler version (GNU++98 sounds quite old compared to GNU++17)? Also, does this affect Swift code?
2
0
408
Feb ’25
Investigating Third-Party IDE Integration Problems
I regularly see questions from folks who’ve run into problems with their third-party IDE on macOS. Specifically, the issue is that their IDE is invoking Apple’s command-line tools — things like clang and ld — and that’s failing in some way. This post collects my ideas on how to investigate, and potentially resolve, issues like this. If you have any questions or comments, please put them in a new thread here on DevForums. Tag it appropriately so that I see it. Good tags include Compiler, Linker, LLVM, and Command Line Tools. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Investigating Third-Party IDE Integration Problems Many third-party IDEs rely on Apple tools. For example, the IDE might run clang to compile C code or run ld to link object files. These IDEs typically don’t include the tools themselves. Rather, they rely on you to install Xcode or Apple’s Command Line Tools package. These are available at Apple > Developer > Downloads Occasionally I see folks having problems with this. They most typically report that basic stuff, like compiling a simple C program, fails with some mysterious error. If you’re having such a problem, follow the steps below to investigate it. IMPORTANT Some IDEs come with their own tools for compiling and linking. Such IDEs are not the focus of this post. If you have problems with an IDE like that, contact its vendor. Select Your Tools macOS has a concept of the current command-line tools. This can either point to the tools within Xcode or to an installed Command Line Tools package. To see which tools are currently selected, run xcode-select with the --print-path argument. This is what you’ll see if you have Xcode installed in the Applications folder: % xcode-select --print-path /Applications/Xcode.app/Contents/Developer Note All of the tools I discuss here are documented in man pages. If you’re not familiar with those, see Reading UNIX Manual Pages. And this is what you’ll see with a Command Line Tools package selected. % xcode-select --print-path /Library/Developer/CommandLineTools There are two common problems with this: It points to something you’ve deleted. It points to something unexpected. Run the command above to see the current state. If necessary, change the state using the --switch option. For example: % xcode-select --print-path /Applications/Xcode.app/Contents/Developer % clang -v Apple clang version 14.0.3 (clang-1403.0.22.14.1) … % sudo xcode-select --switch ~/XcodeZone/Xcode-beta.app % clang -v Apple clang version 15.0.0 (clang-1500.0.38.1) … I have Xcode 14.3 in the Applications folder and thus clang runs Clang 14.0.3. I have Xcode 15.0b5 in ~/XcodeZone, so switching to that yields Clang 15.0.0. It’s possible to run one specific command with different tools. See Select Your Tools Temporarily, below. Run a Simple Test A good diagnostic test is to use the selected command-line tools to compile a trivial test program. Consider this C [1] example: % cat hello.c #include <stdio.h> int main(int argc, char ** argv) { printf("Hello Cruel World!\n"); return 0; } % clang -o hello hello.c % ./hello Hello Cruel World! IMPORTANT If possible, run this from Terminal rather than, say, over SSH. You may need to expand this test program to exercise your specific case. For example, if your program is hitting an error when it tries to import the Core Foundation framework, add that import to your test program: % cat hello.c #include <stdio.h> #include <CoreFoundation/CoreFoundation.h> int main(int argc, char ** argv) { printf("Hello Cruel World!\n"); return 0; } When you compile your test program, you might see one of these results: Your test program compiles. Your test program fails with a similar error. Your test program fails with a different error. I’ll explore each case in turn. [1] For a C++ example, see C++ Issues, below. If your test program compiles… If your test program compiles from the shell, that proves that your basic command-line tools setup is fine. If the same program fails to compile in your IDE, there’s something IDE-specific going on here. I can’t help you with that. I recommend that you escalate the issue via the support channel for your IDE. If your test program fails with a similar error… If your test program fails with an error similar to the one you’re seeing in your IDE, there are two possibilities: There’s a bug in your test program’s code. There’s an environmental issue that’s affecting your command-line tools setup. Don’t rule out the first possibility. I regularly see folks bump into problems like this, where it turns out to be a bug in their code. For a specific example, see C++ Issues, below. Assuming, however, that your test program’s code is OK, it’s time to investigate environmental issues. See Vary Your Environment, below. If your test program fails with a different error… If your test program fails with a different error, look at the test program’s code to confirm that it’s correct, and that it accurately reflects the code you’re trying to run in your IDE. Vary Your Environment If your test program fails with the same error as you’re seeing in your IDE, and you are sure that the code is correct, it’s time to look for environmental factors. I typically do this with the steps described in the next sections, which are listed from most to least complex. These steps only tell you where things are going wrong, not what is going wrong. However, that’s often enough to continue the investigation of your issue. Vary Your Shell Try running your commands in a different shell. macOS’s default shell is zsh. Try running your commands in bash instead: % bash … bash-3.2$ clang -o hello hello.c bash-3.2$ ./hello Hello Cruel World! Or if you’ve switched your shell to bash, try it in zsh. Vary Your User Account Some problems are caused by settings tied to your user account. To investigate whether that’s an issue here: Use System Settings > Users & Groups to create a new user. Log in as that user. Run your test again. Vary Your Mac Some problems are system wide, so you need to test on a different Mac. The easiest way to do that is to set up a virtual machine (VM) and run your test there. Or, if you have a separate physical Mac, run your test on that. Vary Your Site If you’re working for an organisation, they may have installed software on your Mac that causes problems. If you have a Mac at home, try running your test there. It’s also possible that your network is causing problems [1]. If you have a laptop, try taking it to a different location to see if that changes things. [1] I rarely see this when building a simple test program, but it do see it with other stuff, like code signing. C++ Issues If you’re using C++, here’s a simple test you can try: % cat hello.cpp #include <iostream> int main() { std::cout << "Hello Cruel World!\n"; } % clang++ -o hello hello.cpp % ./hello Hello Cruel World! A classic problem with C++ relates to name mangling. Consider this example: % cat hello.c #include <stdio.h> #include "hello-core.h" int main(int argc, char ** argv) { HCSayHello(); return 0; } % cat hello-core.cpp #include "hello-core.h" #include <iostream> extern void HCSayHello() { std::cout << "Hello Cruel World!\n"; } % cat hello-core.h extern void HCSayHello(); % clang -c hello.c % clang++ -c hello-core.cpp % clang++ -o hello hello.o hello-core.o Undefined symbols for architecture x86_64: "_HCSayHello", referenced from: _main in hello.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) The issue here is that C++ generates a mangled name for HCSayHello: % nm hello-core.o | grep HCSayHello 0000000000000000 T __Z10HCSayHellov whereas C uses the non-mangled name: % nm hello.o | grep HCSayHello U _HCSayHello The fix is an appropriate application of extern "C": % cat hello-core.h extern "C" { extern void HCSayHello(); }; Select Your Tools Temporarily Sometimes you want to temporarily run a command from a particular tools package. To continue my earlier example, I currently have Xcode 14.3 installed in the Applications folder and Xcode 15.0b5 in ~/XcodeZone. Xcode 14.3 is the default but I can override that with the DEVELOPER_DIR environment variable: % clang -v Apple clang version 14.0.3 (clang-1403.0.22.14.1) … % DEVELOPER_DIR=~/XcodeZone/Xcode-beta.app/Contents/Developer clang -v Apple clang version 15.0.0 (clang-1500.0.38.1) … Revision History 2025-01-27 Remove the full width characters. These were a workaround for a forums platform bug that’s since been fixed. Made other minor editorial changes. 2023-07-31 First posted.
0
0
1.8k
Jan ’25
[Xcode:BuildSettings] Keep some warnings as warnings while the rest as errors
We have a big iOS project and we are using .xcconfig files to define our compiler options and build settings. We have our SWIFT_TREAT_WARNINGS_AS_ERRORS set to YES so that all Swift related warnings will be reported as errors. Now, we are trying to migrate to Xcode 16.1 and set 'targeted' in the 'Strict Concurrency Checking' flag. This produces some errors that are related to Swift's concurrency checks. We are now planning to have an approach where we still want to keep SWIFT_TREAT_WARNINGS_AS_ERRORS as is but we want all concurrency related warnings to be still treated as warnings while the rest will get reported as errors. We found this new compiler option - https://forums.swift.org/t/warnings-as-errors-exceptions/72925. It looks like the one we want but I think it is still not out yet and we need to wait until Swift 6.1 (correct me if im wrong). Or is there any other way to do what we want to achieve?
0
0
355
Jan ’25
Cannot catch `std::invalid_argument` on clang++ under m1 -fno-rtti
Today I got stuck with a weird behaviour with my c++ project. There is the code which doesn't catch exception from standard library (the same snippet works well on intel mac and under linux machines). Code snippet: #include &lt;exception&gt; #include &lt;stdexcept&gt; #include &lt;iostream&gt; #include &lt;string&gt; int main() { try { std::stod("notanumber"); } catch (const std::invalid_argument&amp;) { std::cerr &lt;&lt; "Caught std::invalid_argument" &lt;&lt; std::endl; } } Compilation command: clang++ -fno-rtti main.cpp -o main &amp;&amp; ./main Clang versions: clang++ --version Homebrew clang version 15.0.3 Target: arm64-apple-darwin21.6.0 Thread model: posix InstalledDir: /opt/homebrew/opt/llvm/bin Also tried: Apple clang version 14.0.0 (clang-1400.0.29.102) Target: arm64-apple-darwin21.6.0 Thread model: posix InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin Output: libc++abi: terminating with uncaught exception of type std::invalid_argument: stod: no conversion [1] 65643 abort ./main Expected output: Caught std::invalid_argument Other info: Chip: Apple M1 OS: 12.6
4
0
1.6k
Dec ’24
Trying to understand Swift-C++ interopability
Hi, I'm struggling to understand using Swift-C++ in the same project. I have an existing code-base that makes heavy use of Swift-Objective-C interoperability. We make use of swift classes in our project. When I enable swift-objective c interoperability I am running into numerous build errors in the generated bridging header. I'm trying to understand why these errors exist and what to do to get around them. I have a project that I've set up with some test code, and I'm running into an error here: public class Foo { let name: String public init(name: String) { self.name = name } } public class Bar { let name: String public init(name : String) { self.name = name; } public func getFoo() -> Foo { return Foo(name: self.name); } } In the header file: Unknown type name 'Foo' SWIFT_INLINE_THUNK Foo getFoo() SWIFT_SYMBOL("s:13ForestBuilder3BarC6getFooAA0E0CyF"); This error goes away if I use structs, but for the purposes of porting my codebase, I'd prefer to use classes. Do classes not play nice here? Or am I misunderstanding something. Thanks.
0
0
444
Dec ’24
XCode 16 clang++ compiler generates unexpected results for conditional checks at -O2 and -O3 optimization levels
Around a month back, developers of the OpenJDK project, when using XCode 16 to build the JDK started noticing odd failures when executing code which was compiled using the clang++ compiler shipped in that XCode 16 release (details in https://bugs.openjdk.org/browse/JDK-8340341). Specifically, a trivial for loop in a c++ code of the form: int limit = ... // method local variable for (i=0; i<limit; i++) { ... } ends up iterating more times than the specified limit. The "i<limit" returns true even when it should have returned false. In fact, debug log messages within the for loop of the form: fprintf(stderr, "parsing %d of %d, %d < % d == %s", i, limit, i, limit, (i<limit) ? "true" : "false"); would show output of the form: parsing 0 of 2, 0 < 2 == true parsing 1 of 2, 1 < 2 == true parsing 2 of 2, 2 < 2 == true Notice, how it entered the for loop even when 2 < 2 should have prevented it from entering it. Furthermore, notice the message says 2 < 2 == true (which clearly isn't right). This happens when that code is compiled with optimization level -O2 or -O3. The issue doesn't happen with -O1. I had reported this as an issue to Apple through feedback assistance, more than a month back. The feedback id is FB15162411. There hasn't been any response to it nor any indication that the issue has been noticed and can be reproduced (the steps to reproduce have been provided in that issue). In the meantime, more and more users are now running into this failure in JDK when using XCode 16. We haven't put any workaround in place (the only workaround we know of is using -O1 for the compilation of this file) because it isn't clear what exactly is causing this issue (other than the fact that it shows up with specific optimization levels). It's also unknown if this bug has wider impact. Would it be possible to check if FB15162411 is being looked into and any technical details on what's causing this? That would help us decide if it's OK to put in place a temporary workaround in the OpenJDK build and how long to maintain that workaround. For reference, this was reproduced on: clang++ --version Apple clang version 16.0.0 (clang-1600.0.26.3) Target: arm64-apple-darwin23.6.0 Thread model: posix InstalledDir: /xcode-16/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
13
1
2.1k
Dec ’24
The Peril of the Ampersand
A few years ago [1] Xcode added new warnings that help detect a nasty gotcha related to the lifetime of unsafe pointers. For example: Initialization of 'UnsafeMutablePointer<timeval>' results in a dangling pointer Inout expression creates a temporary pointer, but argument 'iov_base' should be a pointer that outlives the call to 'init(iov_base:iov_len:)' I’ve seen a lot of folks confused by these warnings, and by the lifetime of unsafe pointers in general, and this post is my attempt to clarify the topic. If you have questions about any of this, please put them in a new thread in the Programming Languages > Swift topic. Finally, I encourage you to watch the following WWDC presentations: WWDC 2020 Session 10648 Unsafe Swift WWDC 2020 Session 10167 Safely manage pointers in Swift These cover some of the same ground I’ve covered here, and a lot of other cool stuff as well. Share and Enjoy — Quinn “The Eskimo!” Apple Developer Relations, Developer Technical Support, Core OS/Hardware let myEmail = "eskimo" + "1" + "@apple.com" [1] Swift 5.2.2, as shipped in Xcode 11.4. See the discussion of SR-2790 in Xcode 11.4 Release Notes. Basics In Swift, the ampersand (&) indicates that a parameter is being passed inout. Consider this example: func addVarnish(_ product: inout String) { product += " varnish" } var waffle = "waffle" addVarnish(&waffle) // line A print(waffle) // printed: waffle varnish On line A, the ampersand tells you that waffle could be modified by addVarnish(_:). However, there is another use of ampersand that was designed to help with C interoperability. Consider this code: var tv = timeval() gettimeofday(&tv, nil) print(tv) // printed: timeval(tv_sec: 1590743104, tv_usec: 77027) The first parameter to gettimeofday is an UnsafeMutablePointer<timeval>. Here the ampersand denotes a conversion from a timeval to an UnsafeMutablePointer<timeval>. This conversion makes it much easier to call common C APIs from Swift. This also works for array values. For example: var hostName = [CChar](repeating: 0, count: 256) gethostname(&hostName, hostName.count) print(String(cString: hostName)) // printed: slimey.local. In this code the ampersand denotes a conversion from [CChar] to an UnsafeMutablePointer<CChar> that points to the base of the array. While this is convenient, it’s potentially misleading, especially if you come from a C background. In C-based languages, using ampersand in this way yields a pointer to the value that’s valid until the value gets deallocated. That’s not the case in Swift. Rather, the pointer generated by the ampersand syntax is only valid for the duration of that function call. To understand why that’s the case, consider this code: struct TimeInTwoParts { var sec: time_t = 0 var usec: Int32 = 0 var combined: timeval { get { timeval(tv_sec: sec, tv_usec: usec) } set { sec = newValue.tv_sec usec = newValue.tv_usec } } } var time = TimeInTwoParts() gettimeofday(&time.combined, nil) // line A print(time.combined) // printed: timeval(tv_sec: 1590743484, tv_usec: 89118) print(time.sec) // printed: 1590743484 print(time.usec) // printed: 89118 Here combined is a computed property that has no independent existence in memory. Thus, it simply makes no sense to take the address of it. So, how does ampersand deal with this? Under the covers the Swift compiler expands line A to something like this: var tmp = time.combined gettimeofday(&tmp, nil) time.combined = tmp Once you understand this it’s clear why the resulting pointer is only valid for the duration of the call: As soon as Swift cleans up tmp, the pointer becomes invalid. A Gotcha This automatic conversion can be a nasty gotcha. Consider this code: var tv = timeval() let tvPtr = UnsafeMutablePointer(&tv) // line A // ^~~~~~~~~~~~~~~~~~~~~~~~~ // Initialization of 'UnsafeMutablePointer<timeval>' results in a dangling pointer gettimeofday(tvPtr, nil) // line B This results in undefined behaviour because the pointer generated by the ampersand on line A is no longer valid when it’s used on line B. In some cases, like this one, the later Swift compiler is able to detect this problem and warn you about it. In other cases you’re not so lucky. Consider this code: guard let f = fopen("tmp.txt", "w") else { … } var buf = [CChar](repeating: 0, count: 1024) setvbuf(f, &buf, _IOFBF, buf.count) // line A let message = [UInt8]("Hello Crueld World!".utf8) fwrite(message, message.count, 1, f) // line B fclose(f) // line C This uses setvbuf to apply a custom buffer to the file handle. The file handle uses this buffer until after the close on line C. However, the pointer created by the ampersand on line A only exists for the duration of the setvbuf call. When the code calls fwrite on line B the buffer pointer is no longer valid and things end badly. Unfortunately the compiler isn’t able to detect this problem. Worse yet, the code might actually work initially, and then stop working as you change optimisation settings, update the compiler, change unrelated code, and so on. Another Gotcha There is another gotcha associated with the ampersand syntax. Consider this code: class AtomicCounter { var count: Int32 = 0 func increment() { OSAtomicAdd32(1, &count) } } This looks like it’ll implement an atomic counter but there’s no guarantee that the counter will be atomic. To understand why, apply the tmp transform from earlier: class AtomicCounter { var count: Int32 = 0 func increment() { var tmp = count OSAtomicAdd32(1, &tmp) count = tmp } } So each call to OSAtomicAdd32 could potentially be operating on a separate copy of the counter that’s then assigned back to count. This undermines the whole notion of atomicity. Again, this might work in some builds of your product and then fail in other builds. Note The above discussion is now theoretical because Swift 6 added a Synchronization module that includes comprehensive support for atomics. That module also has a Mutex type (if you need a mutex on older platforms, check out OSAllocatedUnfairLock). These constructs use various different mechanisms to ensure that the underlying value has a stable address. Summary So, to summarise: Swift’s ampersand syntax has very different semantics from the equivalent syntax in C. When you use an ampersand to convert from a value to a pointer as part of a function call, make sure that the called function doesn’t use the pointer after it’s returned. It is not safe to use the ampersand syntax for functions where the exact pointer matters. It’s Not Just Ampersands There’s one further gotcha related to arrays. The gethostname example above shows that you can use an ampersand to pass the base address of an array to a function that takes a mutable pointer. Swift supports two other implicit conversions like this: From String to UnsafePointer<CChar> — This allows you to pass a Swift string to an API that takes a C string. For example: let greeting = "Hello Cruel World!" let greetingLength = strlen(greeting) print(greetingLength) // printed: 18 From Array<Element> to UnsafePointer<Element> — This allows you to pass a Swift array to a C API that takes an array (in C, arrays are typically represented as a base pointer and a length). For example: let charsUTF16: [UniChar] = [72, 101, 108, 108, 111, 32, 67, 114, 117, 101, 108, 32, 87, 111, 114, 108, 100, 33] print(charsUTF16) let str = CFStringCreateWithCharacters(nil, charsUTF16, charsUTF16.count)! print(str) // prints: Hello Cruel World! Note that there’s no ampersand in either of these examples. This technique only works for UnsafePointer parameters (as opposed to UnsafeMutablePointer parameters), so the called function can’t modify its buffer. As the ampersand is there to indicate that the value might be modified, it’s not used in this immutable case. However, the same pointer lifetime restriction applies: The pointer passed to the function is only valid for the duration of that function call. If the function keeps a copy of that pointer and then uses it later on, Bad Things™ will happen. Consider this code: func printAfterDelay(_ str: UnsafePointer<CChar>) { print(strlen(str)) // printed: 18 DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { print(strlen(str)) // printed: 0 } } let greeting = ["Hello", "Cruel", "World!"].joined(separator: " ") printAfterDelay(greeting) dispatchMain() The second call to strlen yields undefined behaviour because the pointer passed to printAfterDelay(_:) becomes invalid once printAfterDelay(_:) returns. In this specific example the memory pointed to by str happened to contain a zero, and hence strlen returned 0 but that’s not guaranteed. The str pointer is dangling, so you might get any result from strlen, including a crash. Advice So, what can you do about this? There’s two basic strategies here: Extend the lifetime of the pointer Manual memory management Extending the Pointer’s Lifetime The first strategy makes sense when you have a limited number of pointers and their lifespan is limited. For example, you can fix the setvbuf code from above by changing it to: let message = [UInt8]("Hello Crueld World!".utf8) guard let f = fopen("tmp.txt", "w") else { … } var buf = [CChar](repeating: 0, count: 1024) buf.withUnsafeMutableBufferPointer { buf in setvbuf(f, buf.baseAddress!, _IOFBF, buf.count) fwrite(message, message.count, 1, f) fclose(f) } This version of the code uses withUnsafeMutableBufferPointer(_:). That calls the supplied closure and passes it a pointer (actually an UnsafeMutableBufferPointer) that’s valid for the duration of that closure. As long as you only use that pointer inside the closure, you’re safe! There are a variety of other routines like withUnsafeMutableBufferPointer(_:), including: The withUnsafeMutablePointer(to:_:) function The withUnsafeBufferPointer(_:), withUnsafeMutableBufferPointer(_:), withUnsafeBytes(_:), and withUnsafeMutableBytes(_:) methods on Array The withUnsafeBytes(_:) and withUnsafeMutableBytes(_:) methods on Data The withCString(_:) and withUTF8(_:) methods on String. Manual Memory Management If you have to wrangle an unbounded number of pointers — or the lifetime of your pointer isn’t simple, for example when calling an asynchronous call — you must revert to manual memory management. Consider the following code, which is a Swift-friendly wrapper around posix_spawn: func spawn(arguments: [String]) throws -> pid_t { var argv = arguments.map { arg -> UnsafeMutablePointer<CChar>? in strdup(arg) } argv.append(nil) defer { argv.forEach { free($0) } } var pid: pid_t = 0 let success = posix_spawn(&pid, argv[0], nil, nil, argv, environ) == 0 guard success else { throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno), userInfo: nil) } return pid } This code can’t use the withCString(_:) method on String because it has to deal with an arbitrary number of strings. Instead, it uses strdup to copy each string to its own manually managed buffer. And, as these buffers are manually managed, is has to remember to free them. Change History 2024-12-11 Added a note about the Synchronization module. Made various editorial changes. 2021-02-24 Fixed the formatting. Added links to the WWDC 2021 sessions. Fixed the feedback advice. Minor editorial changes. 2020-06-01 Initial version.
0
0
10k
Dec ’24