Obtain the system include directories at runtime
This commit is contained in:
commit
9411a232a4
10 changed files with 99 additions and 34 deletions
|
|
@ -50,9 +50,9 @@ install:
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then tar -xzf cmake-3.3.0-Darwin-x86_64.tar.gz && ls && ls cmake-3.3.0-Darwin-x86_64; fi
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then tar -xzf cmake-3.3.0-Darwin-x86_64.tar.gz && ls && ls cmake-3.3.0-Darwin-x86_64; fi
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export CMAKE=$TRAVIS_BUILD_DIR/../cmake-3.3.0-Darwin-x86_64/CMake.app/Contents/bin/cmake; fi
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export CMAKE=$TRAVIS_BUILD_DIR/../cmake-3.3.0-Darwin-x86_64/CMake.app/Contents/bin/cmake; fi
|
||||||
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then wget --no-check-certificate http://releases.llvm.org/4.0.1/clang+llvm-4.0.1-x86_64-apple-darwin.tar.xz; fi
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then wget --no-check-certificate http://releases.llvm.org/5.0.0/clang+llvm-5.0.0-x86_64-apple-darwin.tar.xz; fi
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then tar -xzf clang+llvm-4.0.1-x86_64-apple-darwin.tar.xz; fi
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then tar -xzf clang+llvm-5.0.0-x86_64-apple-darwin.tar.xz; fi
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export LLVM_CONFIG_BINARY="$TRAVIS_BUILD_DIR/../clang+llvm-4.0.1-x86_64-apple-macosx10.9.0/bin/llvm-config"; fi
|
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export LLVM_CONFIG_BINARY="$TRAVIS_BUILD_DIR/../clang+llvm-5.0.0-x86_64-apple-darwin/bin/llvm-config"; fi
|
||||||
|
|
||||||
- export CXX=$TOOLSET
|
- export CXX=$TOOLSET
|
||||||
- $CXX --version
|
- $CXX --version
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,8 @@ TODO, refer to documentation comments in header file.
|
||||||
|
|
||||||
The library can be used as CMake subdirectory, download it and call `add_subdirectory(path/to/cppast)`, then link to the `cppast` target and enable C++11 or higher.
|
The library can be used as CMake subdirectory, download it and call `add_subdirectory(path/to/cppast)`, then link to the `cppast` target and enable C++11 or higher.
|
||||||
|
|
||||||
The parser needs `libclang` and the `clang++` binary, at least version 3.9.1, but works better with 4.0.0.
|
The parser needs `libclang` and the `clang++` binary, at least version 4.0.0.
|
||||||
|
The `clang++` binary will be found in `PATH` and in the same directory as the program that is being executed.
|
||||||
|
|
||||||
*Note: The project will drop support for older LLVM versions very soon; this minimizes the workaround code when the `libclang` API catches up.*
|
*Note: The project will drop support for older LLVM versions very soon; this minimizes the workaround code when the `libclang` API catches up.*
|
||||||
|
|
||||||
|
|
@ -61,7 +62,10 @@ For that you need to set `LLVM_DOWNLOAD_OS_NAME`.
|
||||||
This is the name of the operating system used on the [LLVM pre-built binary archive](http://releases.llvm.org/download.html#4.0.0), e.g. `x86_64-linux-gnu-ubuntu-16.10` for Ubuntu 16.10.
|
This is the name of the operating system used on the [LLVM pre-built binary archive](http://releases.llvm.org/download.html#4.0.0), e.g. `x86_64-linux-gnu-ubuntu-16.10` for Ubuntu 16.10.
|
||||||
|
|
||||||
If you don't have `llvm-config`, you need to pass the locations explictly.
|
If you don't have `llvm-config`, you need to pass the locations explictly.
|
||||||
For that set the option `LLVM_VERSION_EXPLICIT` to the version you're using, `LIBCLANG_LIBRARY` to the location of the libclang library file, `LIBCLANG_INCLUDE_DIR` to the directory where the header files are located (so they can be included with `clang-c/Index.h`), `LIBCLANG_SYSTEM_INCLUDE_DIR` where the system header files are located (i.e. `stddef.h` etc, usually under `prefix/lib/clang/<version>/include`) and `CLANG_BINARY` to the full path of the `clang++` exectuable.
|
For that set the option `LLVM_VERSION_EXPLICIT` to the version you're using,
|
||||||
|
`LIBCLANG_LIBRARY` to the location of the libclang library file,
|
||||||
|
`LIBCLANG_INCLUDE_DIR` to the directory where the header files are located (so they can be included with `clang-c/Index.h`),
|
||||||
|
and `CLANG_BINARY` to the full path of the `clang++` exectuable.
|
||||||
|
|
||||||
The other dependencies like [type_safe](http://type_safe.foonathan.net) are installed automatically with git submodules, if they're not installed already.
|
The other dependencies like [type_safe](http://type_safe.foonathan.net) are installed automatically with git submodules, if they're not installed already.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ build_script:
|
||||||
- cmd: mkdir build\ && cd build\
|
- cmd: mkdir build\ && cd build\
|
||||||
- cmd: call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
|
- cmd: call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
|
||||||
- cmd: clang++ --version
|
- cmd: clang++ --version
|
||||||
- cmd: cmake -G"Visual Studio 14 2015 Win64" -DLLVM_VERSION_EXPLICIT=4.0.0 -DLIBCLANG_LIBRARY="C:/Program Files/LLVM/lib/libclang.lib" -DLIBCLANG_INCLUDE_DIR="C:/Program Files/LLVM/include" -DLIBCLANG_SYSTEM_INCLUDE_DIR="C:/"Program Files"/LLVM/lib/clang/4.0.0/include" -DCLANG_BINARY="C:/Program Files/LLVM/bin/clang++.exe" ../
|
- cmd: cmake -G"Visual Studio 14 2015 Win64" -DLLVM_VERSION_EXPLICIT=4.0.0 -DLIBCLANG_LIBRARY="C:/Program Files/LLVM/lib/libclang.lib" -DLIBCLANG_INCLUDE_DIR="C:/Program Files/LLVM/include" -DCLANG_BINARY="C:/Program Files/LLVM/bin/clang++.exe" ../
|
||||||
|
|
||||||
- cmd: cmake --build . -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /verbosity:minimal
|
- cmd: cmake --build . -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /verbosity:minimal
|
||||||
|
|
||||||
|
|
|
||||||
15
external/external.cmake
vendored
15
external/external.cmake
vendored
|
|
@ -181,20 +181,6 @@ function(_cppast_find_libclang config_tool min_version force)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# find system header files in llvm_library_dir
|
|
||||||
if(${force})
|
|
||||||
unset(LIBCLANG_SYSTEM_INCLUDE_DIR CACHE)
|
|
||||||
endif()
|
|
||||||
if(NOT LIBCLANG_SYSTEM_INCLUDE_DIR)
|
|
||||||
find_path(LIBCLANG_SYSTEM_INCLUDE_DIR "stddef.h" "${llvm_library_dir}/clang/${llvm_version}/include" NO_DEFAULT_PATH)
|
|
||||||
|
|
||||||
if(NOT LIBCLANG_SYSTEM_INCLUDE_DIR)
|
|
||||||
message(FATAL_ERROR "libclang system header files not found")
|
|
||||||
else()
|
|
||||||
message(STATUS "Found libclang system header files at ${LIBCLANG_SYSTEM_INCLUDE_DIR}")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# find clang binary in llvm_binary_dir
|
# find clang binary in llvm_binary_dir
|
||||||
# note: never override that binary
|
# note: never override that binary
|
||||||
if(NOT CLANG_BINARY)
|
if(NOT CLANG_BINARY)
|
||||||
|
|
@ -238,6 +224,5 @@ add_library(_cppast_libclang INTERFACE)
|
||||||
target_link_libraries(_cppast_libclang INTERFACE ${LIBCLANG_LIBRARY})
|
target_link_libraries(_cppast_libclang INTERFACE ${LIBCLANG_LIBRARY})
|
||||||
target_include_directories(_cppast_libclang INTERFACE ${LIBCLANG_INCLUDE_DIR})
|
target_include_directories(_cppast_libclang INTERFACE ${LIBCLANG_INCLUDE_DIR})
|
||||||
target_compile_definitions(_cppast_libclang INTERFACE
|
target_compile_definitions(_cppast_libclang INTERFACE
|
||||||
CPPAST_LIBCLANG_SYSTEM_INCLUDE_DIR="${LIBCLANG_SYSTEM_INCLUDE_DIR}"
|
|
||||||
CPPAST_CLANG_BINARY="${CLANG_BINARY}"
|
CPPAST_CLANG_BINARY="${CLANG_BINARY}"
|
||||||
CPPAST_CLANG_VERSION_STRING="${LLVM_VERSION}")
|
CPPAST_CLANG_VERSION_STRING="${LLVM_VERSION}")
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,9 @@ public:
|
||||||
/// binary.
|
/// binary.
|
||||||
/// If the binary is not found, it will try and search for it.
|
/// If the binary is not found, it will try and search for it.
|
||||||
/// \returns `true` if the binary was found exactly as specified.
|
/// \returns `true` if the binary was found exactly as specified.
|
||||||
/// \notes It will be used for preprocessing.
|
/// \notes This binary will be used for preprocessing as well as determining the default include
|
||||||
|
/// directories. As such, if it is called after include directories have already been added, the
|
||||||
|
/// order might end up being wrong.
|
||||||
bool set_clang_binary(std::string binary);
|
bool set_clang_binary(std::string binary);
|
||||||
|
|
||||||
/// \effects Sets whether or not the preprocessed file will be written out.
|
/// \effects Sets whether or not the preprocessed file will be written out.
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,9 @@ bool libclang_compilation_database::has_config(const char* file_name) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{} // namespace
|
||||||
|
|
||||||
libclang_compile_config::libclang_compile_config()
|
libclang_compile_config::libclang_compile_config()
|
||||||
: compile_config({}), write_preprocessed_(false), fast_preprocessing_(false),
|
: compile_config({}), write_preprocessed_(false), fast_preprocessing_(false),
|
||||||
remove_comments_in_macro_(false)
|
remove_comments_in_macro_(false)
|
||||||
|
|
@ -83,9 +86,6 @@ libclang_compile_config::libclang_compile_config()
|
||||||
// set given clang binary
|
// set given clang binary
|
||||||
set_clang_binary(CPPAST_CLANG_BINARY);
|
set_clang_binary(CPPAST_CLANG_BINARY);
|
||||||
|
|
||||||
// set system include dir
|
|
||||||
add_include_dir(CPPAST_LIBCLANG_SYSTEM_INCLUDE_DIR);
|
|
||||||
|
|
||||||
// set macros to detect cppast
|
// set macros to detect cppast
|
||||||
define_macro("__cppast__", "libclang");
|
define_macro("__cppast__", "libclang");
|
||||||
define_macro("__cppast_version_major__", CPPAST_VERSION_MAJOR);
|
define_macro("__cppast_version_major__", CPPAST_VERSION_MAJOR);
|
||||||
|
|
@ -252,6 +252,65 @@ bool is_valid_binary(const std::string& binary)
|
||||||
[](const char*, std::size_t) {});
|
[](const char*, std::size_t) {});
|
||||||
return process.get_exit_status() == 0;
|
return process.get_exit_status() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)
|
||||||
|
# define CPPAST_DETAIL_WINDOWS 1
|
||||||
|
#else
|
||||||
|
# define CPPAST_DETAIL_WINDOWS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void add_default_include_dirs(libclang_compile_config& config)
|
||||||
|
{
|
||||||
|
std::string verbose_output;
|
||||||
|
tpl::Process process(detail::libclang_compile_config_access::clang_binary(config)
|
||||||
|
+ " -x c++ -v -",
|
||||||
|
"", [](const char*, std::size_t) {},
|
||||||
|
[&](const char* str, std::size_t n) { verbose_output.append(str, n); },
|
||||||
|
true);
|
||||||
|
process.write("", 1);
|
||||||
|
process.close_stdin();
|
||||||
|
process.get_exit_status();
|
||||||
|
|
||||||
|
auto pos = verbose_output.find("#include <...>");
|
||||||
|
DEBUG_ASSERT(pos != std::string::npos, detail::assert_handler{});
|
||||||
|
while (verbose_output[pos] != '\n')
|
||||||
|
++pos;
|
||||||
|
++pos;
|
||||||
|
|
||||||
|
// now every line is an include path, starting with a space
|
||||||
|
while (verbose_output[pos] == ' ')
|
||||||
|
{
|
||||||
|
auto start = pos + 1;
|
||||||
|
while (verbose_output[pos] != '\r' && verbose_output[pos] != '\n')
|
||||||
|
++pos;
|
||||||
|
auto end = pos;
|
||||||
|
++pos;
|
||||||
|
|
||||||
|
auto line = verbose_output.substr(start, end - start);
|
||||||
|
std::string path;
|
||||||
|
for (auto c : line)
|
||||||
|
{
|
||||||
|
if (c == ' ')
|
||||||
|
{ // escape spaces
|
||||||
|
#if CPPAST_DETAIL_WINDOWS
|
||||||
|
path += "^ ";
|
||||||
|
#else
|
||||||
|
path += "\\ ";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
// clang under MacOS adds comments to paths using '(' at the end, so they have to be
|
||||||
|
// ignored however, Windows uses '(' in paths, so they don't have to be ignored
|
||||||
|
#if !CPPAST_DETAIL_WINDOWS
|
||||||
|
else if (c == '(')
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
path += c;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.add_include_dir(std::move(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
bool libclang_compile_config::set_clang_binary(std::string binary)
|
bool libclang_compile_config::set_clang_binary(std::string binary)
|
||||||
|
|
@ -259,6 +318,7 @@ bool libclang_compile_config::set_clang_binary(std::string binary)
|
||||||
if (is_valid_binary(binary))
|
if (is_valid_binary(binary))
|
||||||
{
|
{
|
||||||
clang_binary_ = binary;
|
clang_binary_ = binary;
|
||||||
|
add_default_include_dirs(*this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -271,6 +331,7 @@ bool libclang_compile_config::set_clang_binary(std::string binary)
|
||||||
if (is_valid_binary(p))
|
if (is_valid_binary(p))
|
||||||
{
|
{
|
||||||
clang_binary_ = p;
|
clang_binary_ = p;
|
||||||
|
add_default_include_dirs(*this);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@ std::string get_macro_command(const libclang_compile_config& c, const char* full
|
||||||
// other flags
|
// other flags
|
||||||
for (auto& flag : detail::libclang_compile_config_access::flags(c))
|
for (auto& flag : detail::libclang_compile_config_access::flags(c))
|
||||||
{
|
{
|
||||||
cmd += flag;
|
cmd += quote(flag);
|
||||||
cmd += ' ';
|
cmd += ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ TEST_CASE("stdlib", "[!hide][integration]")
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <new>
|
//#include <new> -- something weird going on here
|
||||||
#include <scoped_allocator>
|
#include <scoped_allocator>
|
||||||
|
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
|
|
@ -110,7 +110,7 @@ TEST_CASE("stdlib", "[!hide][integration]")
|
||||||
REQUIRE(!parser.error());
|
REQUIRE(!parser.error());
|
||||||
REQUIRE(file);
|
REQUIRE(file);
|
||||||
|
|
||||||
REQUIRE(resolve_includes(parser, file.value(), config) == 62);
|
REQUIRE(resolve_includes(parser, file.value(), config) == 61);
|
||||||
REQUIRE(!parser.error());
|
REQUIRE(!parser.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,15 @@ void require_flags(const libclang_compile_config& config, const char* flags)
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
auto config_flags = detail::libclang_compile_config_access::flags(config);
|
auto config_flags = detail::libclang_compile_config_access::flags(config);
|
||||||
// skip first 4, those are the default options
|
// skip until including __cppast_version__minor__, those are the default options
|
||||||
for (auto iter = config_flags.begin() + 4; iter != config_flags.end(); ++iter)
|
auto in_default = true;
|
||||||
|
for (auto iter = config_flags.begin(); iter != config_flags.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (*iter == "-D__cppast_version_minor__=\"" CPPAST_VERSION_MINOR "\"")
|
||||||
|
in_default = false;
|
||||||
|
else if (!in_default)
|
||||||
result += *iter + ' ';
|
result += *iter + ' ';
|
||||||
|
}
|
||||||
result.pop_back();
|
result.pop_back();
|
||||||
REQUIRE(result == flags);
|
REQUIRE(result == flags);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,21 @@ inline void write_file(const char* name, const char* code)
|
||||||
file << code;
|
file << code;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::unique_ptr<cppast::cpp_file> parse_file(const cppast::cpp_entity_index& idx,
|
inline cppast::libclang_compile_config make_test_config()
|
||||||
const char* name,
|
|
||||||
bool fast_preprocessing = false)
|
|
||||||
{
|
{
|
||||||
using namespace cppast;
|
using namespace cppast;
|
||||||
|
|
||||||
libclang_compile_config config;
|
libclang_compile_config config;
|
||||||
config.set_flags(cpp_standard::cpp_latest);
|
config.set_flags(cpp_standard::cpp_latest);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::unique_ptr<cppast::cpp_file> parse_file(const cppast::cpp_entity_index& idx,
|
||||||
|
const char* name,
|
||||||
|
bool fast_preprocessing = false)
|
||||||
|
{
|
||||||
|
using namespace cppast;
|
||||||
|
static auto config = make_test_config();
|
||||||
config.fast_preprocessing(fast_preprocessing);
|
config.fast_preprocessing(fast_preprocessing);
|
||||||
|
|
||||||
libclang_parser p(default_logger());
|
libclang_parser p(default_logger());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue