mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
This updates the Bazel toolchain logic to work on macOS. Much like on Linux, I'm not testing this against a *released* LLVM, but against a from-source build. You can build and install LLVM from top-of-tree locally with CMake, or on macOS maybe use Homebrew like: ``` brew install llvm --HEAD ``` You then need to point Bazel to the installed `clang` executable if it is not placed onto your PATH (Homebrew doesn't): ``` bazel test --repo_env=CC=$HOME/homebrew/opt/llvm/bin/clang //parser:all ``` This builds and passes tests for me at least. The fuzzer feature may not work (yet) with this setup, but that can be improved incrementally as we proceed.
100 lines
2.5 KiB
C++
100 lines
2.5 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#include "source/source_buffer.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include <cerrno>
|
|
#include <cstdint>
|
|
#include <system_error>
|
|
|
|
#include "llvm/ADT/ScopeExit.h"
|
|
|
|
namespace Carbon {
|
|
|
|
auto SourceBuffer::CreateFromText(llvm::Twine text, llvm::StringRef filename)
|
|
-> SourceBuffer {
|
|
return SourceBuffer(filename, text.str());
|
|
}
|
|
|
|
static auto ErrnoToError(int errno_value) -> llvm::Error {
|
|
return llvm::errorCodeToError(
|
|
std::error_code(errno_value, std::generic_category()));
|
|
}
|
|
|
|
auto SourceBuffer::CreateFromFile(llvm::StringRef filename)
|
|
-> llvm::Expected<SourceBuffer> {
|
|
SourceBuffer buffer(filename);
|
|
|
|
errno = 0;
|
|
int file_descriptor = open(buffer.filename_.c_str(), O_RDONLY);
|
|
if (file_descriptor == -1) {
|
|
return ErrnoToError(errno);
|
|
}
|
|
|
|
// Now that we have an open file, we need to close it on any error.
|
|
auto closer =
|
|
llvm::make_scope_exit([file_descriptor] { close(file_descriptor); });
|
|
|
|
struct stat stat_buffer = {};
|
|
errno = 0;
|
|
if (fstat(file_descriptor, &stat_buffer) == -1) {
|
|
return ErrnoToError(errno);
|
|
}
|
|
|
|
int64_t size = stat_buffer.st_size;
|
|
if (size == 0) {
|
|
// Nothing to do for an empty file.
|
|
return {std::move(buffer)};
|
|
}
|
|
|
|
errno = 0;
|
|
void* mapped_text = mmap(nullptr, size, PROT_READ,
|
|
#ifdef __APPLE__
|
|
MAP_PRIVATE,
|
|
#else
|
|
MAP_PRIVATE | MAP_POPULATE,
|
|
#endif
|
|
file_descriptor, /*offset=*/0);
|
|
if (mapped_text == MAP_FAILED) {
|
|
return ErrnoToError(errno);
|
|
}
|
|
|
|
errno = 0;
|
|
closer.release();
|
|
if (close(file_descriptor) == -1) {
|
|
// Try to unmap the text. No errer handling as this is just best-effort
|
|
// cleanup.
|
|
munmap(mapped_text, size);
|
|
return ErrnoToError(errno);
|
|
}
|
|
|
|
buffer.text_ = llvm::StringRef(static_cast<const char*>(mapped_text), size);
|
|
assert(!buffer.text_.empty() &&
|
|
"Must not have an empty text when we have mapped data from a file!");
|
|
return {std::move(buffer)};
|
|
}
|
|
|
|
SourceBuffer::~SourceBuffer() {
|
|
if (is_string_rep_) {
|
|
string_storage_.~decltype(string_storage_)();
|
|
return;
|
|
}
|
|
|
|
if (!text_.empty()) {
|
|
errno = 0;
|
|
int result =
|
|
munmap(const_cast<void*>(static_cast<const void*>(text_.data())),
|
|
text_.size());
|
|
(void)result;
|
|
assert(result != -1 && "Unmapping text failed!");
|
|
}
|
|
}
|
|
|
|
} // namespace Carbon
|