Merge changes from topic "versioner_cpp"
* changes: versioner: compile headers in both C and C++ mode. versioner: follow __asm__ labels.
This commit is contained in:
commit
48228fb572
17 changed files with 127 additions and 31 deletions
|
@ -1,6 +1,8 @@
|
|||
cc_binary_host {
|
||||
name: "versioner",
|
||||
|
||||
cpp_std: "gnu++17",
|
||||
|
||||
srcs: [
|
||||
"versioner.cpp",
|
||||
"Arch.cpp",
|
||||
|
@ -29,6 +31,7 @@ cc_binary_host {
|
|||
"-Wextra",
|
||||
"-Werror",
|
||||
"-Wno-unused-parameter",
|
||||
"-fno-omit-frame-pointer",
|
||||
|
||||
"-D__STDC_CONSTANT_MACROS",
|
||||
"-D__STDC_LIMIT_MACROS",
|
||||
|
@ -37,7 +40,6 @@ cc_binary_host {
|
|||
target: {
|
||||
host: {
|
||||
cppflags: [
|
||||
"-std=gnu++1z",
|
||||
"-fno-rtti",
|
||||
],
|
||||
},
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
std::string to_string(const CompilationType& type) {
|
||||
std::stringstream ss;
|
||||
ss << to_string(type.arch) << "-" << type.api_level << " [fob = " << type.file_offset_bits << "]";
|
||||
ss << to_string(type.arch) << "-" << type.api_level << " [" << (type.cpp ? "c++" : "c")
|
||||
<< ", fob = " << type.file_offset_bits << "]";
|
||||
return ss.str();
|
||||
}
|
||||
|
|
|
@ -25,12 +25,13 @@
|
|||
|
||||
struct CompilationType {
|
||||
Arch arch;
|
||||
bool cpp;
|
||||
int api_level;
|
||||
int file_offset_bits;
|
||||
|
||||
private:
|
||||
auto tie() const {
|
||||
return std::tie(arch, api_level, file_offset_bits);
|
||||
return std::tie(arch, cpp, api_level, file_offset_bits);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -49,11 +50,13 @@ struct hash<CompilationType> {
|
|||
size_t operator()(CompilationType type) const {
|
||||
struct {
|
||||
int32_t arch : 3;
|
||||
int32_t cpp : 1;
|
||||
int32_t api_level : 6;
|
||||
int32_t file_offset_bits : 1;
|
||||
int32_t padding : 22;
|
||||
int32_t padding : 21;
|
||||
} packed;
|
||||
packed.arch = static_cast<int32_t>(type.arch);
|
||||
packed.cpp = type.cpp;
|
||||
packed.api_level = type.api_level;
|
||||
packed.file_offset_bits = (type.file_offset_bits == 64);
|
||||
packed.padding = 0;
|
||||
|
|
|
@ -35,6 +35,22 @@
|
|||
|
||||
using namespace clang;
|
||||
|
||||
static bool shouldMangle(MangleContext* mangler, NamedDecl* decl) {
|
||||
// Passing a decl with static linkage to the mangler gives incorrect results.
|
||||
// Check some things ourselves before handing it off to the mangler.
|
||||
if (auto FD = dyn_cast<FunctionDecl>(decl)) {
|
||||
if (FD->isExternC()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FD->isInExternCContext()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return mangler->shouldMangleDeclName(decl);
|
||||
}
|
||||
|
||||
class Visitor : public RecursiveASTVisitor<Visitor> {
|
||||
HeaderDatabase& database;
|
||||
CompilationType type;
|
||||
|
@ -54,9 +70,14 @@ class Visitor : public RecursiveASTVisitor<Visitor> {
|
|||
}
|
||||
}
|
||||
|
||||
// <math.h> maps fool onto foo on 32-bit, since long double is the same as double.
|
||||
if (auto asm_attr = decl->getAttr<AsmLabelAttr>()) {
|
||||
return asm_attr->getLabel();
|
||||
}
|
||||
|
||||
// The decl might not have a name (e.g. bitfields).
|
||||
if (auto identifier = decl->getIdentifier()) {
|
||||
if (mangler->shouldMangleDeclName(decl)) {
|
||||
if (shouldMangle(mangler.get(), decl)) {
|
||||
std::string mangled;
|
||||
llvm::raw_string_ostream ss(mangled);
|
||||
mangler->mangleName(decl, ss);
|
||||
|
|
|
@ -98,9 +98,16 @@ static void generateTargetCC1Flags(llvm::IntrusiveRefCntPtr<clang::vfs::FileSyst
|
|||
CompilationType type,
|
||||
const std::vector<std::string>& include_dirs) {
|
||||
std::vector<std::string> cmd = { "versioner" };
|
||||
cmd.push_back("-std=c11");
|
||||
cmd.push_back("-x");
|
||||
cmd.push_back("c");
|
||||
if (type.cpp) {
|
||||
cmd.push_back("-std=gnu++11");
|
||||
cmd.push_back("-x");
|
||||
cmd.push_back("c++");
|
||||
} else {
|
||||
cmd.push_back("-std=gnu11");
|
||||
cmd.push_back("-x");
|
||||
cmd.push_back("c");
|
||||
}
|
||||
|
||||
cmd.push_back("-fsyntax-only");
|
||||
|
||||
cmd.push_back("-Wall");
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
@ -82,18 +83,28 @@ static int getCpuCount() {
|
|||
|
||||
namespace {
|
||||
struct HeaderLocationInformation {
|
||||
std::string header_dir;
|
||||
std::string header_path;
|
||||
std::string dependency_dir;
|
||||
// Absolute paths to ignore all children -- including subdirectories -- of.
|
||||
std::unordered_set<std::string> ignored_directories;
|
||||
};
|
||||
}
|
||||
|
||||
static bool is_dir(const std::string& path) {
|
||||
struct stat st;
|
||||
return stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
||||
static CompilationRequirements collectRequirements(const Arch& arch,
|
||||
const HeaderLocationInformation& location) {
|
||||
std::vector<std::string> headers =
|
||||
collectHeaders(location.header_dir, location.ignored_directories);
|
||||
std::vector<std::string> dependencies = { location.header_dir };
|
||||
collectHeaders(location.header_path, location.ignored_directories);
|
||||
std::vector<std::string> dependencies;
|
||||
|
||||
if (is_dir(location.header_path)) {
|
||||
dependencies.emplace_back(location.header_path);
|
||||
}
|
||||
|
||||
if (!location.dependency_dir.empty()) {
|
||||
auto collect_children = [&dependencies](const std::string& dir_path) {
|
||||
DIR* dir = opendir(dir_path.c_str());
|
||||
|
@ -159,10 +170,12 @@ static std::set<CompilationType> generateCompilationTypes(const std::set<Arch> s
|
|||
}
|
||||
|
||||
for (int file_offset_bits : { 32, 64 }) {
|
||||
CompilationType type = {
|
||||
.arch = arch, .api_level = api_level, .file_offset_bits = file_offset_bits
|
||||
};
|
||||
result.insert(type);
|
||||
for (bool cpp : { true, false }) {
|
||||
CompilationType type = {
|
||||
.arch = arch, .cpp = cpp, .api_level = api_level, .file_offset_bits = file_offset_bits
|
||||
};
|
||||
result.insert(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +188,7 @@ static std::unique_ptr<HeaderDatabase> compileHeaders(const std::set<Compilation
|
|||
errx(1, "compileHeaders received no CompilationTypes");
|
||||
}
|
||||
|
||||
auto vfs = createCommonVFS(location.header_dir, location.dependency_dir, add_include);
|
||||
auto vfs = createCommonVFS(location.header_path, location.dependency_dir, add_include);
|
||||
|
||||
size_t thread_count = max_thread_count;
|
||||
std::vector<std::thread> threads;
|
||||
|
@ -282,7 +295,8 @@ static bool checkSymbol(const Symbol& symbol) {
|
|||
for (const auto& inline_def_it : inline_definitions) {
|
||||
auto intersection = Intersection(compilation_types, inline_def_it.second);
|
||||
if (!intersection.empty()) {
|
||||
fprintf(stderr, "versioner: conflicting inline definitions:\n");
|
||||
fprintf(stderr, "versioner: conflicting inline definitions for symbol %s:\n",
|
||||
symbol.name.c_str());
|
||||
fprintf(stderr, " declarations visible in: %s\n", Join(intersection, ", ").c_str());
|
||||
decl->dump(cwd, stderr, 4);
|
||||
inline_def_it.first->dump(cwd, stderr, 4);
|
||||
|
@ -526,8 +540,8 @@ int main(int argc, char** argv) {
|
|||
if (stat(platform_dir.c_str(), &st) != 0) {
|
||||
err(1, "failed to stat platform directory '%s'", platform_dir.c_str());
|
||||
}
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
errx(1, "'%s' is not a directory", optarg);
|
||||
if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) {
|
||||
errx(1, "'%s' is not a file or directory", optarg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -598,13 +612,13 @@ int main(int argc, char** argv) {
|
|||
if (optind == argc) {
|
||||
// Neither HEADER_PATH nor DEPS_PATH were specified, so try to figure them out.
|
||||
std::string versioner_dir = to_string(top) + "/bionic/tools/versioner";
|
||||
location.header_dir = versioner_dir + "/current";
|
||||
location.header_path = versioner_dir + "/current";
|
||||
location.dependency_dir = versioner_dir + "/dependencies";
|
||||
if (platform_dir.empty()) {
|
||||
platform_dir = versioner_dir + "/platforms";
|
||||
}
|
||||
} else {
|
||||
if (!android::base::Realpath(argv[optind], &location.header_dir)) {
|
||||
if (!android::base::Realpath(argv[optind], &location.header_path)) {
|
||||
err(1, "failed to get realpath for path '%s'", argv[optind]);
|
||||
}
|
||||
|
||||
|
@ -616,8 +630,8 @@ int main(int argc, char** argv) {
|
|||
// Every file that lives in bits/fortify is logically a part of a header outside of bits/fortify.
|
||||
// This makes the files there impossible to build on their own.
|
||||
if (ignore_fortify_headers) {
|
||||
std::string fortify_path = location.header_dir;
|
||||
if (!android::base::EndsWith(location.header_dir, "/")) {
|
||||
std::string fortify_path = location.header_path;
|
||||
if (!android::base::EndsWith(location.header_path, "/")) {
|
||||
fortify_path += '/';
|
||||
}
|
||||
fortify_path += "bits/fortify";
|
||||
|
@ -634,10 +648,8 @@ int main(int argc, char** argv) {
|
|||
|
||||
|
||||
struct stat st;
|
||||
if (const char *dir = location.header_dir.c_str(); stat(dir, &st) != 0) {
|
||||
err(1, "failed to stat '%s'", dir);
|
||||
} else if (!S_ISDIR(st.st_mode)) {
|
||||
errx(1, "'%s' is not a directory", dir);
|
||||
if (const char *path = location.header_path.c_str(); stat(path, &st) != 0) {
|
||||
err(1, "failed to stat '%s'", path);
|
||||
}
|
||||
|
||||
std::set<CompilationType> compilation_types;
|
||||
|
@ -663,7 +675,7 @@ int main(int argc, char** argv) {
|
|||
|
||||
bool failed = false;
|
||||
if (dump) {
|
||||
declaration_database->dump(location.header_dir + "/");
|
||||
declaration_database->dump(location.header_path + "/");
|
||||
} else {
|
||||
if (!sanityCheck(declaration_database.get())) {
|
||||
printf("versioner: sanity check failed\n");
|
||||
|
@ -679,7 +691,8 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
if (!preprocessor_output_path.empty() && (force || !failed)) {
|
||||
failed = !preprocessHeaders(preprocessor_output_path, location.header_dir, declaration_database.get());
|
||||
failed = !preprocessHeaders(preprocessor_output_path, location.header_path,
|
||||
declaration_database.get());
|
||||
}
|
||||
return failed;
|
||||
}
|
||||
|
|
18
tools/versioner/tests/extern_cpp/headers/string.h
Normal file
18
tools/versioner/tests/extern_cpp/headers/string.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define __RENAME(x) __asm__(#x)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C++" char* basename(char*) __RENAME(__gnu_basename) __INTRODUCED_IN(23);
|
||||
extern "C++" const char* basename(const char*) __RENAME(__gnu_basename) __INTRODUCED_IN(23);
|
||||
#else
|
||||
char* basename(const char*) __RENAME(__gnu_basename) __INTRODUCED_IN(23);
|
||||
#endif
|
||||
|
||||
char* foo() __INTRODUCED_IN(8);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
__gnu_basename
|
1
tools/versioner/tests/extern_cpp/run.sh
Normal file
1
tools/versioner/tests/extern_cpp/run.sh
Normal file
|
@ -0,0 +1 @@
|
|||
versioner headers -p platforms -r arm -a 21 -a 23 -i
|
16
tools/versioner/tests/extern_cpp_mismatch/headers/string.h
Normal file
16
tools/versioner/tests/extern_cpp_mismatch/headers/string.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define __RENAME(x) __asm__(#x)
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C++" char* basename(char*) __RENAME(__gnu_basename) __INTRODUCED_IN(23);
|
||||
extern "C++" const char* basename(const char*) __RENAME(__gnu_basename) __INTRODUCED_IN(23);
|
||||
#else
|
||||
char* basename(const char*) __RENAME(__gnu_basename) __INTRODUCED_IN(23);
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1 @@
|
|||
foo
|
1
tools/versioner/tests/extern_cpp_mismatch/run.sh
Normal file
1
tools/versioner/tests/extern_cpp_mismatch/run.sh
Normal file
|
@ -0,0 +1 @@
|
|||
versioner headers -p platforms -r arm -a 9 -i
|
|
@ -1,5 +1,5 @@
|
|||
versioner: conflicting inline definitions:
|
||||
declarations visible in: arm-9 [fob = 32], arm-9 [fob = 64], arm-12 [fob = 32], arm-12 [fob = 64]
|
||||
versioner: conflicting inline definitions for symbol foo:
|
||||
declarations visible in: arm-9 [c, fob = 32], arm-9 [c, fob = 64], arm-12 [c, fob = 32], arm-12 [c, fob = 64], arm-9 [c++, fob = 32], arm-9 [c++, fob = 64], arm-12 [c++, fob = 32], arm-12 [c++, fob = 64]
|
||||
static definition @ headers/foo.h:5:1
|
||||
no availability
|
||||
static definition @ headers/bar.h:5:1
|
||||
|
|
8
tools/versioner/tests/unnamed_bitfield/headers/foo.h
Normal file
8
tools/versioner/tests/unnamed_bitfield/headers/foo.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
// <sys/timex.h> was causing a segfault when compiled in C++ mode because
|
||||
// versioner was trying to mangle the name of an unnamed bitfield.
|
||||
struct foo {
|
||||
int : 32;
|
||||
int : 32;
|
||||
int : 32;
|
||||
int : 32;
|
||||
};
|
|
@ -0,0 +1 @@
|
|||
foo
|
1
tools/versioner/tests/unnamed_bitfield/run.sh
Normal file
1
tools/versioner/tests/unnamed_bitfield/run.sh
Normal file
|
@ -0,0 +1 @@
|
|||
versioner headers -p platforms -r arm -a 9 -i
|
Loading…
Reference in a new issue