Add support for C language standards (#159)

This commit is contained in:
Lucas Jansen 2023-01-26 11:17:44 +00:00 committed by GitHub
commit 7b25525232
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 147 additions and 11 deletions

View file

@ -82,7 +82,7 @@ libclang_compile_config::libclang_compile_config() : libclang_compile_config(CPP
libclang_compile_config::libclang_compile_config(std::string clang_binary)
: compile_config({}), write_preprocessed_(false), fast_preprocessing_(false),
remove_comments_in_macro_(false)
remove_comments_in_macro_(false), use_c_(false)
{
// set given clang binary
set_clang_binary(clang_binary);
@ -226,6 +226,11 @@ cppast::libclang_compile_config::libclang_compile_config(
for (auto i = 0u; i != size; ++i)
{
auto cmd = clang_CompileCommands_getCommand(commands.get(), i);
// If ++ exists within the compiler name (e.g. clang++, g++, etc), use C++
std::string exe(clang_getCString(clang_CompileCommand_getArg(cmd, 0)));
use_c_ = (exe.find("++", 0) == std::string::npos);
auto dir = detail::cxstring(clang_CompileCommand_getDirectory(cmd));
parse_flags(cmd, [&](std::string flag, std::string args) {
if (flag == "-I")
@ -243,11 +248,21 @@ cppast::libclang_compile_config::libclang_compile_config(
add_flag(std::move(flag));
}
else if (flag == "-std")
// standard
{
use_c_ = (args.find("++") == std::string::npos);
add_flag(std::move(flag) + "=" + std::move(args));
}
else if (flag == "-f")
// other options
add_flag(std::move(flag) + std::move(args));
else if (flag == "-x")
{
// language
if (args == "c")
use_c_ = true;
else
use_c_ = false;
}
});
}
}
@ -270,8 +285,9 @@ bool is_valid_binary(const std::string& binary)
void add_default_include_dirs(libclang_compile_config& config)
{
std::string verbose_output;
std::string language = config.use_c() ? "-xc" : "-xc++";
tpl::Process process(
detail::libclang_compile_config_access::clang_binary(config) + " -x c++ -v -", "",
detail::libclang_compile_config_access::clang_binary(config) + " " + language + " -v -", "",
[](const char*, std::size_t) {},
[&](const char* str, std::size_t n) { verbose_output.append(str, n); }, true);
process.write("", 1);
@ -424,6 +440,57 @@ void libclang_compile_config::do_set_flags(cpp_standard standard, compile_flags
add_flag("-std=c++2a");
break;
}
else
throw std::invalid_argument("c++2b is not yet supported for current version of clang");
case cpp_standard::c_89:
if (flags & compile_flag::gnu_extensions)
add_flag("-std=gnu89");
else
add_flag("-std=c89");
break;
case cpp_standard::c_99:
if (flags & compile_flag::gnu_extensions)
add_flag("-std=gnu99");
else
add_flag("-std=c99");
break;
case cpp_standard::c_11:
if (flags & compile_flag::gnu_extensions)
add_flag("-std=gnu11");
else
add_flag("-std=c11");
break;
case cpp_standard::c_17:
if (libclang_parser::libclang_minor_version() >= 45)
{ // Corresponds to Clang version 6
if (flags & compile_flag::gnu_extensions)
add_flag("-std=gnu17");
else
add_flag("-std=c17");
break;
}
else
throw std::invalid_argument("c17 is not yet supported for current version of clang");
case cpp_standard::c_2x:
if (libclang_parser::libclang_minor_version() >= 59)
{ // Corresponds to Clang version 9
if (flags & compile_flag::gnu_extensions)
add_flag("-std=gnu2x");
else
add_flag("-std=c2x");
break;
}
else
throw std::invalid_argument("c2x is not yet supported for current version of clang");
}
// Add language flag for C or C++
if (is_c_standard(standard)) {
add_flag("-xc");
use_c_ = true;
} else {
add_flag("-xc++");
use_c_ = false;
}
if (flags & compile_flag::ms_compatibility)
@ -461,6 +528,11 @@ void libclang_compile_config::do_remove_macro_definition(std::string name)
add_flag("-U" + std::move(name));
}
bool libclang_compile_config::do_use_c() const noexcept
{
return use_c_;
}
type_safe::optional<libclang_compile_config> cppast::find_config_for(
const libclang_compilation_database& database, std::string file_name)
{
@ -474,7 +546,7 @@ type_safe::optional<libclang_compile_config> cppast::find_config_for(
if (database.has_config(file_name))
return libclang_compile_config(database, std::move(file_name));
static const char* extensions[]
= {".h", ".hpp", ".cpp", ".h++", ".c++", ".hxx", ".cxx", ".hh", ".cc", ".H", ".C"};
= {".h", ".hpp", ".cpp", ".h++", ".c++", ".hxx", ".cxx", ".hh", ".cc", ".H", ".C", ".c"};
for (auto ext : extensions)
{
auto name = file_name + ext;
@ -511,8 +583,8 @@ namespace
std::vector<const char*> get_arguments(const libclang_compile_config& config)
{
std::vector<const char*> args
// TODO: Why? and Why?
= {"-x", "c++", "-I."}; // force C++ and enable current directory for include search
// TODO: Why?
= {"-I."}; // enable current directory for include search
for (auto& flag : detail::libclang_compile_config_access::flags(config))
args.push_back(flag.c_str());
return args;

View file

@ -174,11 +174,12 @@ std::string diagnostics_flags()
// get the command that returns all macros defined in the TU
std::string get_macro_command(const libclang_compile_config& c, const char* full_path)
{
// -x c++: force C++ as input language
// -xc/-xc++: force C or C++ as input language
// -I.: add current working directory to include search path
// -E: print preprocessor output
// -dM: print macro definitions instead of preprocessed file
auto flags = std::string("-x c++ -I. -E -dM");
std::string language = c.use_c() ? "-xc" : "-xc++";
auto flags = language + " -I. -E -dM";
flags += diagnostics_flags();
std::string cmd(detail::libclang_compile_config_access::clang_binary(c) + " " + std::move(flags)
@ -198,10 +199,11 @@ std::string get_macro_command(const libclang_compile_config& c, const char* full
std::string get_preprocess_command(const libclang_compile_config& c, const char* full_path,
const char* macro_file_path)
{
// -x c++: force C++ as input language
// -xc/-xc++: force C or C++ as input language
// -E: print preprocessor output
// -dD: keep macros
auto flags = std::string("-x c++ -E -dD");
std::string language = c.use_c() ? "-xc" : "-xc++";
auto flags = language + " -E -dD";
// -CC: keep comments, even in macro
// -C: keep comments, but not in macro