diff --git a/src/messages/initialize.cc b/src/messages/initialize.cc index 74db461f..016ad68c 100644 --- a/src/messages/initialize.cc +++ b/src/messages/initialize.cc @@ -86,12 +86,15 @@ struct InitializeHandler : BaseMessageHandler { // Ensure there is a resource directory. if (config->resourceDirectory.empty()) { - config->resourceDirectory = GetWorkingDirectory(); -#if defined(_WIN32) - config->resourceDirectory += std::string("../../clang_resource_dir/"); -#else - config->resourceDirectory += std::string("../clang_resource_dir/"); -#endif + std::string defaultResourceDirectory = std::string(DEFAULT_RESOURCE_DIRECTORY); + if (defaultResourceDirectory.find("..") != std::string::npos) { + std::string executablePath = GetExecutablePath(); + size_t pos = executablePath.find_last_of('/'); + config->resourceDirectory = executablePath.substr(0, pos+1); + config->resourceDirectory += defaultResourceDirectory; + } else { + config->resourceDirectory = defaultResourceDirectory; + } } config->resourceDirectory = NormalizePath(config->resourceDirectory); LOG_S(INFO) << "Using -resource-dir=" << config->resourceDirectory; diff --git a/src/platform.h b/src/platform.h index 0df07d25..8525e1d4 100644 --- a/src/platform.h +++ b/src/platform.h @@ -31,6 +31,7 @@ std::unique_ptr CreatePlatformSharedMemory( void PlatformInit(); +std::string GetExecutablePath(); std::string GetWorkingDirectory(); std::string NormalizePath(const std::string& path); // Creates a directory at |path|. Creates directories recursively if needed. diff --git a/src/platform_linux.cc b/src/platform_linux.cc index c84ff1eb..1e7b37bc 100644 --- a/src/platform_linux.cc +++ b/src/platform_linux.cc @@ -210,6 +210,27 @@ std::unique_ptr CreatePlatformSharedMemory( void PlatformInit() {} +#ifdef __APPLE__ +extern "C" int _NSGetExecutablePath(char* buf,uint32_t* bufsize); +#endif + +// See https://stackoverflow.com/questions/143174/how-do-i-get-the-directory-that-a-program-is-running-from +std::string GetExecutablePath() { +#ifndef __APPLE__ + char buffer[PATH_MAX+1] = {0}; + readlink("/proc/self/exe", buffer, PATH_MAX); + return std::string(buffer); +#else + uint32_t size = 0; + _NSGetExecutablePath(nullptr, &size); + char *buffer = new char[size]; + _NSGetExecutablePath(buffer, &size); + std::string result(buffer); + delete[] buffer; + return result; +#endif +} + std::string GetWorkingDirectory() { char result[FILENAME_MAX]; if (!getcwd(result, sizeof(result))) diff --git a/src/platform_win.cc b/src/platform_win.cc index f62c1032..5c4cab3b 100644 --- a/src/platform_win.cc +++ b/src/platform_win.cc @@ -127,6 +127,13 @@ void PlatformInit() { _setmode(_fileno(stdin), O_BINARY); } +// See https://stackoverflow.com/questions/143174/how-do-i-get-the-directory-that-a-program-is-running-from +std::string GetExecutablePath() { + char result[MAX_PATH] = {0}; + GetModuleFileName(NULL, result, MAX_PATH); + return std::string(result); +} + // See http://stackoverflow.com/a/19535628 std::string GetWorkingDirectory() { char result[MAX_PATH]; diff --git a/wscript b/wscript index f7b283cb..d06c2425 100644 --- a/wscript +++ b/wscript @@ -10,6 +10,7 @@ import os.path import string import subprocess import sys +import re VERSION = '0.0.1' APPNAME = 'cquery' @@ -198,11 +199,25 @@ def build(bld): lib.append('pthread') clang_tarball_name = None + # Fallback for windows + default_resource_directory = os.path.join(os.getcwd(), 'resource_dir') if bld.env['use_system_clang']: rpath = [] + + output = subprocess.check_output(['clang', '-###', '-xc', '/dev/null'], stderr=subprocess.STDOUT) + match = re.search(r'"-resource-dir" "([^"]*)"', output, re.M | re.I) + if match: + default_resource_directory = match.group(1) + else: + print("Failed to found system clang resource directory. Falling back.") elif sys.platform.startswith('freebsd') or sys.platform.startswith('linux'): clang_tarball_name = os.path.basename(os.path.dirname(bld.env['LIBPATH_clang'][0])) rpath = '$ORIGIN/../lib/' + clang_tarball_name + '/lib' + default_resource_directory = '../lib/' + clang_tarball_name + '/resource-dir' + elif sys.platform == 'darwin': + clang_tarball_name = os.path.basename(os.path.dirname(bld.env['LIBPATH_clang'][0])) + rpath = '@loader_path/../lib/' + clang_tarball_name + '/lib' + default_resource_directory = '../lib/' + clang_tarball_name + '/resource-dir' else: rpath = bld.env['LIBPATH_clang'] bld.program( @@ -216,15 +231,15 @@ def build(bld): 'third_party/rapidjson/include/', 'third_party/sparsehash/src/', 'third_party/sparsepp/'], - defines=['LOGURU_WITH_STREAMS=1'], + defines=['LOGURU_WITH_STREAMS=1', + 'DEFAULT_RESOURCE_DIRECTORY="' + default_resource_directory + '"'], lib=lib, rpath=rpath, target='bin/cquery') - if bld.cmd == 'install': - if clang_tarball_name is not None: - bld.install_files('${PREFIX}/lib/' + clang_tarball_name + '/lib', bld.path.get_bld().ant_glob('lib/clang+llvm*/lib/libclang.so.[4-9]')) - bld.install_files('${PREFIX}/lib/' + clang_tarball_name + '/resource-dir/include', bld.path.get_bld().ant_glob('lib/clang+llvm*/lib/clang/[4-9]*/include/*')) + if clang_tarball_name is not None: + bld.install_files('${PREFIX}/lib/' + clang_tarball_name + '/lib', bld.path.get_bld().ant_glob('lib/' + clang_tarball_name + '/lib/libclang.(dylib|so.[4-9])', quiet=True)) + bld.install_files('${PREFIX}/lib/' + clang_tarball_name + '/resource-dir/include', bld.path.get_bld().ant_glob('lib/' + clang_tarball_name + '/lib/clang/[4-9]*/include/*', quiet=True)) #bld.shlib(source='a.cpp', target='mylib', vnum='9.8.7') #bld.shlib(source='a.cpp', target='mylib2', vnum='9.8.7', cnum='9.8')