Skip to content

Commit

Permalink
Path autodetection (#41)
Browse files Browse the repository at this point in the history
* Fix for issue #37 - removing the cwd being set to the source file being processed.
* Adding `use-system-clang` flag (among 5 in total)
  • Loading branch information
fosterbrereton authored Aug 30, 2019
1 parent 3de5342 commit 75587be
Show file tree
Hide file tree
Showing 6 changed files with 454 additions and 47 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ There are several modes under which the tool can run:
- `-hyde-src-root = <path>` - The root path to the header file(s) being analyzed. Affects `defined-in-file` output values by taking out the root path.
- `-hyde-yaml-dir = <path>` - Root directory for YAML validation / update. Required for either hyde-validate or hyde-update modes.

- `use-system-clang` - Autodetect and use necessary resource directories and include paths

This tool parses the passed header using Clang. To pass arguments to the compiler (e.g., include directories), append them after the `--` token on the command line. For example:

hyde input_file.hpp -hyde-json -- -x c++ -I/path/to/includes
hyde input_file.hpp -hyde-json -use-system-clang -- -x c++ -I/path/to/includes

Alternatively, if you have a compilation database and would like to pass that instead of command-line compiler arguments, you can pass that with `-p`.

Expand All @@ -60,10 +62,10 @@ While compiling the source file, the non-function macro `ADOBE_TOOL_HYDE` is def
# Examples:

To output JSON:
```./hyde ../test_files/classes.cpp --```
```./hyde -use-system-clang ../test_files/classes.cpp --```

To validate pre-existing YAML:
```./hyde ../test_files/classes.cpp -hyde-yaml-dir=/path/to/output -hyde-validate```
```./hyde -use-system-clang -hyde-yaml-dir=/path/to/output -hyde-validate ../test_files/classes.cpp```

To output updated YAML:
```./hyde ../test_files/classes.cpp -hyde-yaml-dir=/path/to/output -hyde-update```
```./hyde -use-system-clang -hyde-yaml-dir=/path/to/output -hyde-update ../test_files/classes.cpp```
40 changes: 40 additions & 0 deletions include/autodetect.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Copyright 2018 Adobe
All Rights Reserved.
NOTICE: Adobe permits you to use, modify, and distribute this file in
accordance with the terms of the Adobe license agreement accompanying
it. If you have received this file from a source other than Adobe,
then your use, modification, or distribution of it requires the prior
written permission of Adobe.
*/

#pragma once

// stdc++
#include <string>
#include <vector>

// application
#include "config.hpp"
#include "filesystem.hpp"

/**************************************************************************************************/

namespace hyde {

/**************************************************************************************************/

std::vector<filesystem::path> autodetect_toolchain_paths();

filesystem::path autodetect_resource_directory();

#if HYDE_PLATFORM(APPLE)
filesystem::path autodetect_sysroot_directory();
#endif // HYDE_PLATFORM(APPLE)

/**************************************************************************************************/

} // namespace hyde

/**************************************************************************************************/
32 changes: 32 additions & 0 deletions include/config.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
Copyright 2018 Adobe
All Rights Reserved.
NOTICE: Adobe permits you to use, modify, and distribute this file in
accordance with the terms of the Adobe license agreement accompanying
it. If you have received this file from a source other than Adobe,
then your use, modification, or distribution of it requires the prior
written permission of Adobe.
*/

#pragma once

/**************************************************************************************************/

#define HYDE_PRIVATE_STRING_XSMASH(X, Y) X##Y
#define HYDE_PRIVATE_STRING_SMASH(X, Y) HYDE_PRIVATE_STRING_XSMASH(X, Y)()

#define HYDE_PLATFORM_PRIVATE_APPLE() 0
#define HYDE_PLATFORM_PRIVATE_MICROSOFT() 0

#define HYDE_PLATFORM(X) HYDE_PRIVATE_STRING_SMASH(HYDE_PLATFORM_PRIVATE_, X)

#if defined(__APPLE__)
#undef HYDE_PLATFORM_PRIVATE_APPLE
#define HYDE_PLATFORM_PRIVATE_APPLE() 1
#elif defined(_MSC_VER)
#undef HYDE_PLATFORM_PRIVATE_MICROSOFT
#define HYDE_PLATFORM_PRIVATE_MICROSOFT() 1
#endif

/**************************************************************************************************/
80 changes: 80 additions & 0 deletions include/filesystem.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
Copyright 2018 Adobe
All Rights Reserved.
NOTICE: Adobe permits you to use, modify, and distribute this file in
accordance with the terms of the Adobe license agreement accompanying
it. If you have received this file from a source other than Adobe,
then your use, modification, or distribution of it requires the prior
written permission of Adobe.
*/

/**************************************************************************************************/

#pragma once

/**************************************************************************************************/

#define HYDE_FILESYSTEM_PRIVATE_STD() 0
#define HYDE_FILESYSTEM_PRIVATE_STD_EXPERIMENTAL() 1
#define HYDE_FILESYSTEM_PRIVATE_BOOST() 2

/**************************************************************************************************/

#if defined(STLAB_FORCE_BOOST_FILESYSTEM)
#define HYDE_FILESYSTEM_PRIVATE_SELECTION() HYDE_FILESYSTEM_PRIVATE_BOOST()
#elif defined(__has_include) // Check if __has_include is present
#if __has_include(<filesystem>)
#include <filesystem>
#define HYDE_FILESYSTEM_PRIVATE_SELECTION() HYDE_FILESYSTEM_PRIVATE_STD()
#elif __has_include(<experimental/filesystem>)
#include <experimental/filesystem>
#define HYDE_FILESYSTEM_PRIVATE_SELECTION() HYDE_FILESYSTEM_PRIVATE_STD_EXPERIMENTAL()
#else
#define HYDE_FILESYSTEM_PRIVATE_SELECTION() HYDE_FILESYSTEM_PRIVATE_BOOST()
#endif
#else
#define HYDE_FILESYSTEM_PRIVATE_SELECTION() HYDE_FILESYSTEM_PRIVATE_BOOST()
#endif

#define HYDE_FILESYSTEM(X) (HYDE_FILESYSTEM_PRIVATE_SELECTION() == HYDE_FILESYSTEM_PRIVATE_##X())

/**************************************************************************************************/
// The library can be used with boost::filesystem, std::experimental::filesystem or std::filesystem.
// Without any additional define, it uses the versions from the standard, if it is available.
//
// If using of boost::filesystem shall be enforced, define STLAB_FORCE_BOOST_FILESYSTEM.

#if HYDE_FILESYSTEM(BOOST)
#include <boost/filesystem.hpp>
#endif

/**************************************************************************************************/

namespace hyde {

/**************************************************************************************************/

#if HYDE_FILESYSTEM(STD)

namespace filesystem = std::filesystem;

#elif HYDE_FILESYSTEM(STD_EXPERIMENTAL)

namespace filesystem = std::experimental::filesystem;

#elif HYDE_FILESYSTEM(BOOST)

namespace filesystem = boost::filesystem;

#else

#error `filesystem` variant not specified

#endif

/**************************************************************************************************/

} // namespace hyde

/**************************************************************************************************/
170 changes: 170 additions & 0 deletions sources/autodetect.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
/*
Copyright 2018 Adobe
All Rights Reserved.
NOTICE: Adobe permits you to use, modify, and distribute this file in
accordance with the terms of the Adobe license agreement accompanying
it. If you have received this file from a source other than Adobe,
then your use, modification, or distribution of it requires the prior
written permission of Adobe.
*/

// identity
#include "autodetect.hpp"

// stdc++
#include <array>

namespace filesystem = hyde::filesystem;

/**************************************************************************************************/

namespace {

/**************************************************************************************************/

std::vector<std::string> split(const char* p, std::size_t n) {
auto end = p + n;
std::vector<std::string> result;

while (p != end) {
while (p != end && *p == '\n') ++p; // eat newlines
auto begin = p;
while (p != end && *p != '\n') ++p; // eat non-newlines
result.emplace_back(begin, p);
}

return result;
}

/**************************************************************************************************/

std::vector<std::string> file_slurp(boost::filesystem::path p) {
boost::filesystem::ifstream s(p);
s.seekg(0, std::ios::end);
std::size_t size = s.tellg();
auto buffer{std::make_unique<char[]>(size)};
s.seekg(0);
s.read(&buffer[0], size);
return split(buffer.get(), size);
}

/**************************************************************************************************/

std::string trim_front(std::string s) {
std::size_t n(0);
std::size_t end(s.size());

while (n != end && (std::isspace(s[n]) || s[n] == '\n'))
++n;

s.erase(0, n);

return s;
}

/**************************************************************************************************/

std::string trim_back(std::string s) {
std::size_t start(s.size());

while (start != 0 && (std::isspace(s[start - 1]) || s[start - 1] == '\n'))
start--;

s.erase(start, std::string::npos);

return s;
}

/**************************************************************************************************/

std::string chomp(std::string src) {
return trim_back(trim_front(std::move(src)));
}

/**************************************************************************************************/

std::string exec(const char* cmd) {
std::array<char, 128> buffer;
std::string result;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
if (!pipe) {
throw std::runtime_error("popen() failed!");
}
while (fgets(buffer.data(), buffer.size(), pipe.get())) {
result += buffer.data();
}
return chomp(std::move(result));
}

/**************************************************************************************************/

std::vector<filesystem::path> autodetect_include_paths() {
auto temp_dir = boost::filesystem::temp_directory_path();
auto temp_path = temp_dir / "hyde.tmp";
auto temp_path_str = temp_path.string();
auto command = "echo \"int main() { }\" | clang++ -x c++ -v - 2> " + temp_path_str;

std::system(command.c_str());

std::vector lines(file_slurp(temp_path));
static const std::string begin_string("#include <...> search starts here:");
static const std::string end_string("End of search list.");
auto paths_begin = std::find(begin(lines), end(lines), begin_string);
auto paths_end = std::find(begin(lines), end(lines), end_string);
std::vector<filesystem::path> result;

if (paths_begin != end(lines) && paths_end != end(lines)) {
lines.erase(paths_end, end(lines));
lines.erase(begin(lines), next(paths_begin));

// lines.erase(std::remove_if(begin(lines), end(lines), [](auto& s){
// return s.find(".sdk/") != std::string::npos;
// }), end(lines));

// Some of the paths contain cruft at the end. Filter those out, too.
std::transform(begin(lines), end(lines), std::back_inserter(result), [](auto s){
static const std::string needle_k{" (framework directory)"};
auto needle_pos = s.find(needle_k);
if (needle_pos != std::string::npos) {
s.erase(needle_pos);
}
return filesystem::path(chomp(std::move(s)));
});
}

return result;
}

/**************************************************************************************************/

} // namespace

/**************************************************************************************************/

namespace hyde {

/**************************************************************************************************/

std::vector<filesystem::path> autodetect_toolchain_paths() {
return autodetect_include_paths();
}

/**************************************************************************************************/

boost::filesystem::path autodetect_resource_directory() {
return boost::filesystem::path{exec("clang++ -print-resource-dir")};
}

/**************************************************************************************************/
#if HYDE_PLATFORM(APPLE)
boost::filesystem::path autodetect_sysroot_directory() {
return boost::filesystem::path{exec("xcode-select -p")} /
"Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk";
}
#endif // HYDE_PLATFORM(APPLE)
/**************************************************************************************************/

} // namespace hyde

/**************************************************************************************************/
Loading

0 comments on commit 75587be

Please sign in to comment.