Add Appveyor CI

This commit is contained in:
Jonathan Müller 2017-04-21 12:47:06 +02:00
commit 9a906d5e0c
14 changed files with 95 additions and 43 deletions

View file

@ -56,6 +56,9 @@ If you don't have a proper clang version installed, it can also be downloaded.
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.
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.
The other dependencies like [type_safe](http://type_safe.foonathan.net) are installed automatically with git submodules, if they're not installed already.
If you run into any issues with the installation, please report them.

11
appveyor.yml Normal file
View file

@ -0,0 +1,11 @@
version: '{build}'
build_script:
- cmd: mkdir build\ && cd build\
- cmd: call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
- 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 --build . -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
test_script:
- cmd: test\Debug\cppast_test.exe

View file

@ -150,19 +150,16 @@ function(_cppast_find_libclang config_tool min_version force)
endif()
endfunction()
# create libclang target
# target: _cppast_libclang
function(_cppast_create_libclang_target library_path include_path)
add_library(_cppast_libclang SHARED IMPORTED)
set_target_properties(_cppast_libclang PROPERTIES
IMPORTED_LOCATION ${library_path}
INTERFACE_INCLUDE_DIRECTORIES ${include_path})
endfunction()
set(llvm_min_version 3.9.1)
set(LLVM_PREFERRED_VERSION 4.0.0 CACHE STRING "the preferred LLVM version")
if(NOT LLVM_CONFIG_BINARY)
if(DEFINED LLVM_VERSION_EXPLICIT)
if(LLVM_VERSION_EXPLICIT VERSION_LESS llvm_min_version)
message(FATAL_ERROR "Outdated LLVM version ${LLVM_VERSION_EXPLICIT}, minimal supported is ${llvm_min_version}")
endif()
set(LLVM_VERSION ${LLVM_VERSION_EXPLICIT} CACHE INTERNAL "")
message(STATUS "Using manually specified LLVM version ${LLVM_VERSION}")
elseif(NOT LLVM_CONFIG_BINARY)
if(DEFINED LLVM_DOWNLOAD_OS_NAME)
_cppast_download_llvm(${LLVM_PREFERRED_VERSION} ${LLVM_DOWNLOAD_OS_NAME})
endif()
@ -172,4 +169,10 @@ else()
_cppast_find_libclang(${LLVM_CONFIG_BINARY} ${llvm_min_version} 0)
endif()
_cppast_create_libclang_target(${LIBCLANG_LIBRARY} ${LIBCLANG_INCLUDE_DIR})
add_library(_cppast_libclang INTERFACE)
target_link_libraries(_cppast_libclang INTERFACE ${LIBCLANG_LIBRARY})
target_include_directories(_cppast_libclang INTERFACE ${LIBCLANG_INCLUDE_DIR})
target_compile_definitions(_cppast_libclang INTERFACE
CPPAST_LIBCLANG_SYSTEM_INCLUDE_DIR="${LIBCLANG_SYSTEM_INCLUDE_DIR}"
CPPAST_CLANG_BINARY="${CLANG_BINARY}"
CPPAST_CLANG_VERSION_STRING="${LLVM_VERSION}")

View file

@ -109,20 +109,14 @@ namespace cppast
using token_seq = detail::semantic_string_view<struct token_seq_tag>;
/// Tag type to represent an end-of-line character.
constexpr struct newl_t
const struct newl_t
{
constexpr newl_t() noexcept
{
}
} newl;
} newl{};
/// Tag type to represent a single space character.
constexpr struct whitespace_t
const struct whitespace_t
{
constexpr whitespace_t() noexcept
{
}
} whitespace;
} whitespace{};
/// Base class to control the code generation.
///

View file

@ -54,7 +54,7 @@ namespace cppast
/// \notes This may include template parameters.
std::string semantic_scope() const noexcept
{
return semantic_parent_.map(&cpp_entity_ref::name).value_or("");
return type_safe::copy(semantic_parent_.map(&cpp_entity_ref::name)).value_or("");
}
protected:

View file

@ -101,9 +101,6 @@ add_library(cppast ${detail_header} ${header} ${source} ${libclang_source})
target_include_directories(cppast PUBLIC ../include)
target_link_libraries(cppast PUBLIC type_safe _cppast_tiny_process _cppast_libclang)
target_compile_definitions(cppast PUBLIC
CPPAST_LIBCLANG_SYSTEM_INCLUDE_DIR="${LIBCLANG_SYSTEM_INCLUDE_DIR}"
CPPAST_CLANG_BINARY="${CLANG_BINARY}"
CPPAST_CLANG_VERSION_STRING="${LLVM_VERSION}"
CPPAST_VERSION_STRING="${cppast_VERSION}")
if(CPPAST_ENABLE_ASSERTIONS)
target_compile_definitions(cppast PUBLIC CPPAST_ENABLE_ASSERTIONS)

View file

@ -137,10 +137,12 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_class(const detail::parse_context&
add_base_class(builder, context, child, cur);
else if (kind == CXCursor_CXXFinalAttr)
builder.is_final();
else if (kind == CXCursor_TemplateTypeParameter
|| kind == CXCursor_NonTypeTemplateParameter
|| kind == CXCursor_TemplateTemplateParameter || kind == CXCursor_ParmDecl
|| clang_isExpression(kind) || clang_isReference(kind))
else if (
kind == CXCursor_TemplateTypeParameter || kind == CXCursor_NonTypeTemplateParameter
|| kind == CXCursor_TemplateTemplateParameter || kind == CXCursor_ParmDecl
|| clang_isExpression(kind) || clang_isReference(kind)
|| kind
== CXCursor_UnexposedAttr) // I have no idea what this is, but happens on Windows
// other children due to templates and stuff
return;
else if (auto entity = parse_entity(context, child))

View file

@ -333,6 +333,8 @@ namespace
else
stream.bump();
}
if (stream.peek() == "{" || stream.peek() == ":" || stream.peek() == "try")
result.body_kind = cpp_function_definition;
}
else
{
@ -356,6 +358,9 @@ namespace
if (detail::skip_if(stream, "="))
parse_body(stream, result, allow_virtual);
else if (detail::skip_if(stream, "{") || detail::skip_if(stream, ":")
|| detail::skip_if(stream, "try"))
result.body_kind = cpp_function_definition;
}
return result;

View file

@ -28,7 +28,10 @@ namespace cppast
return CXChildVisit_Recurse;
};
clang_visitChildren(parent, recurse ? recurse_lambda : continue_lambda, &f);
if (recurse)
clang_visitChildren(parent, recurse_lambda, &f);
else
clang_visitChildren(parent, continue_lambda, &f);
}
// visits a translation unit

View file

@ -7,6 +7,7 @@
#include <algorithm>
#include <cstddef>
#include <cstring>
#include <cctype>
#include <process.hpp>
@ -650,17 +651,24 @@ detail::preprocessor_output detail::preprocess(const libclang_compile_config& co
position p(ts::ref(result.source), output.c_str());
std::size_t file_depth = 0u;
ts::flag in_string(false);
ts::flag in_string(false), in_char(false);
while (p)
{
if (starts_with(p, "\\\"")) // starts with \"
p.bump(2u);
else if (starts_with(p, "\"")) // starts with "
else if (starts_with(p, "\\'")) // starts with \'
p.bump(2u);
else if (in_char == false && starts_with(p, "\"")) // starts with "
{
p.bump();
in_string.toggle();
}
else if (in_string == true)
else if (in_string == false && starts_with(p, "'"))
{
p.bump();
in_char.toggle();
}
else if (in_string == true || in_char == true)
p.bump();
else if (auto macro = parse_macro(p, result, file_depth == 0u))
{

View file

@ -4,6 +4,8 @@
#include "tokenizer.hpp"
#include <cctype>
#include "libclang_visitor.hpp"
#include "parse_error.hpp"
@ -92,7 +94,7 @@ namespace
auto kind = clang_getCursorKind(cur);
if (cursor_is_function(kind) || cursor_is_function(clang_getTemplateCursorKind(cur)))
{
auto range_shrunk = false;
auto is_definition = false;
// if a function we need to remove the body
// it does not need to be parsed
@ -103,11 +105,22 @@ namespace
{
auto child_extent = clang_getCursorExtent(child);
end = clang_getRangeStart(child_extent);
range_shrunk = true;
is_definition = true;
}
});
if (!range_shrunk && !token_after_is(tu, file, cur, end, ";"))
if (!is_definition)
{
// i have no idea why this is necessary
is_definition = token_after_is(tu, file, cur, end, "{")
|| token_after_is(tu, file, cur, end, "try")
|| token_after_is(tu, file, cur, end, ":");
if (is_definition)
// need to extend range here to include the token
end = get_next_location(tu, file, end);
}
if (!is_definition && !token_after_is(tu, file, cur, end, ";"))
{
// we do not have a body, but it is not a declaration either
do

View file

@ -4,6 +4,8 @@
#include "parse_functions.hpp"
#include <cctype>
#include <cppast/cpp_array_type.hpp>
#include <cppast/cpp_decltype_type.hpp>
#include <cppast/cpp_expression.hpp>

View file

@ -77,21 +77,29 @@ enum ns::c : int {};
++no_vals;
REQUIRE(val.value());
auto& expr = val.value().value();
REQUIRE(expr.kind() == cpp_expression_kind::unexposed_t);
REQUIRE(static_cast<const cpp_unexposed_expression&>(expr).expression()
== "42");
REQUIRE(equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_uint)));
if (equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_uint)))
{
REQUIRE(expr.kind() == cpp_expression_kind::unexposed_t);
REQUIRE(static_cast<const cpp_unexposed_expression&>(expr).expression()
== "42");
}
else
{
REQUIRE(equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_int)));
REQUIRE(expr.kind() == cpp_expression_kind::literal_t);
REQUIRE(static_cast<const cpp_literal_expression&>(expr).value() == "42");
}
}
else if (val.name() == "a_d")
{
++no_vals;
REQUIRE(val.value());
auto& expr = val.value().value();
// this is unexposed for some reason
REQUIRE(expr.kind() == cpp_expression_kind::unexposed_t);
REQUIRE(static_cast<const cpp_unexposed_expression&>(expr).expression()
== "a_a+2");
REQUIRE(equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_uint)));
if (!equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_int)))
REQUIRE(equal_types(idx, expr.type(), *cpp_builtin_type::build(cpp_uint)));
}
else
REQUIRE(false);

View file

@ -145,7 +145,10 @@ struct a {};
/// u
/** b
* b */
void b(int, float);
void b(int, float)
{
auto c = '#';
}
/** u */
//! c