source: CLRX/CLRadeonExtender/trunk/utils/Utilities.cpp @ 3221

Last change on this file since 3221 was 3221, checked in by matszpk, 3 years ago

CLRadeonExtender: Fix warnings for new clang 4.0.0 (obsolete instantations of specializations).

File size: 21.3 KB
Line 
1/*
2 *  CLRadeonExtender - Unofficial OpenCL Radeon Extensions Library
3 *  Copyright (C) 2014-2017 Mateusz Szpakowski
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2.1 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <CLRX/Config.h>
21#if defined(HAVE_LINUX) || defined(HAVE_BSD)
22#include <dlfcn.h>
23#endif
24#ifdef HAVE_WINDOWS
25#include <direct.h>
26#include <windows.h>
27#include <shlobj.h>
28#else
29#include <pwd.h>
30#include <unistd.h>
31#include <sys/stat.h>
32#include <sys/wait.h>
33#endif
34#include <fstream>
35#include <fcntl.h>
36#include <sys/stat.h>
37#include <mutex>
38#include <cerrno>
39#include <cstring>
40#include <string>
41#include <climits>
42#define __UTILITIES_MODULE__ 1
43#include <CLRX/utils/Utilities.h>
44
45using namespace CLRX;
46
47Exception::Exception(const std::string& _message) : message(_message)
48{ }
49
50const char* Exception::what() const noexcept
51{
52    return message.c_str();
53}
54
55ParseException::ParseException(const std::string& message) : Exception(message)
56{ }
57
58ParseException::ParseException(LineNo lineNo, const std::string& message)
59{
60    char buf[32];
61    itocstrCStyle(lineNo, buf, 32);
62    this->message = buf;
63    this->message += ": ";
64    this->message += message;
65}
66
67ParseException::ParseException(LineNo lineNo, ColNo charNo, const std::string& message)
68{
69    char buf[32];
70    itocstrCStyle(lineNo, buf, 32);
71    this->message = buf;
72    this->message += ": ";
73    itocstrCStyle(charNo, buf, 32);
74    this->message += buf;
75    this->message += ": ";
76    this->message += message;
77}
78
79std::mutex CLRX::DynLibrary::mutex;
80
81DynLibrary::DynLibrary() : handle(nullptr)
82{ }
83
84DynLibrary::DynLibrary(const char* filename, Flags flags) : handle(nullptr)
85{
86    load(filename, flags);
87}
88
89DynLibrary::~DynLibrary()
90{
91    unload();
92}
93
94void DynLibrary::load(const char* filename, Flags flags)
95{
96    std::lock_guard<std::mutex> lock(mutex);
97#if defined(HAVE_LINUX) || defined(HAVE_BSD)
98    dlerror(); // clear old errors
99    int outFlags = (flags & DYNLIB_GLOBAL) ? RTLD_GLOBAL : RTLD_LOCAL;
100    if ((flags & DYNLIB_MODE1_MASK) == DYNLIB_LAZY)
101        outFlags |= RTLD_LAZY;
102    if ((flags & DYNLIB_MODE1_MASK) == DYNLIB_NOW)
103        outFlags |= RTLD_NOW;
104    handle = dlopen(filename, outFlags);
105    if (handle == nullptr)
106        throw Exception(dlerror());
107#endif
108#ifdef HAVE_WINDOWS
109    handle = (void*)LoadLibrary(filename);
110    if (handle == nullptr)
111        throw Exception("DynLibrary::load failed");
112#endif
113}
114
115void DynLibrary::unload()
116{
117    std::lock_guard<std::mutex> lock(mutex);
118    if (handle != nullptr)
119    {
120#if defined(HAVE_LINUX) || defined(HAVE_BSD)
121        dlerror(); // clear old errors
122        if (dlclose(handle)) // if closing failed
123            throw Exception(dlerror());
124#endif
125#ifdef HAVE_WINDOWS
126        if (!FreeLibrary((HMODULE)handle))
127            throw Exception("DynLibrary::unload failed");
128#endif
129    }
130    handle = nullptr;
131}
132
133void* DynLibrary::getSymbol(const char* symbolName)
134{
135    if (handle == nullptr)
136        throw Exception("DynLibrary not loaded!");
137   
138    std::lock_guard<std::mutex> lock(mutex);
139    void* symbol = nullptr;
140#if defined(HAVE_LINUX) || defined(HAVE_BSD)
141    dlerror(); // clear old errors
142    symbol = dlsym(handle, symbolName);
143    const char* error = dlerror();
144    if (symbol == nullptr && error != nullptr)
145        throw Exception(error);
146#endif
147#ifdef HAVE_WINDOWS
148    symbol = (void*)GetProcAddress((HMODULE)handle, symbolName);
149    if (symbol==nullptr)
150        throw Exception("DynLibrary::getSymbol failed");
151#endif
152    return symbol;
153}
154
155template
156cxuchar CLRX::parseEnvVariable<cxuchar>(const char* envVar,
157                const cxuchar& defaultValue);
158
159template
160cxchar CLRX::parseEnvVariable<cxchar>(const char* envVar,
161              const cxchar& defaultValue);
162
163
164template
165cxuint CLRX::parseEnvVariable<cxuint>(const char* envVar,
166               const cxuint& defaultValue);
167
168template
169cxint CLRX::parseEnvVariable<cxint>(const char* envVar,
170               const cxint& defaultValue);
171
172template
173cxushort CLRX::parseEnvVariable<cxushort>(const char* envVar,
174               const cxushort& defaultValue);
175
176template
177cxshort CLRX::parseEnvVariable<cxshort>(const char* envVar,
178               const cxshort& defaultValue);
179
180template
181cxulong CLRX::parseEnvVariable<cxulong>(const char* envVar,
182               const cxulong& defaultValue);
183
184template
185cxlong CLRX::parseEnvVariable<cxlong>(const char* envVar,
186               const cxlong& defaultValue);
187
188template
189cxullong CLRX::parseEnvVariable<cxullong>(const char* envVar,
190               const cxullong& defaultValue);
191
192template
193cxllong CLRX::parseEnvVariable<cxllong>(const char* envVar,
194               const cxllong& defaultValue);
195
196template
197float CLRX::parseEnvVariable<float>(const char* envVar,
198            const float& defaultValue);
199
200template
201double CLRX::parseEnvVariable<double>(const char* envVar,
202              const double& defaultValue);
203
204
205namespace CLRX
206{
207template<>
208std::string parseEnvVariable<std::string>(const char* envVar,
209              const std::string& defaultValue)
210{
211    const char* var = getenv(envVar);
212    if (var == nullptr)
213        return defaultValue;
214    return var;
215}
216
217template<>
218bool parseEnvVariable<bool>(const char* envVar, const bool& defaultValue)
219{
220    const char* var = getenv(envVar);
221    if (var == nullptr)
222        return defaultValue;
223   
224    // skip spaces
225    for (; *var == ' ' || *var == '\t' || *var == '\r'; var++);
226   
227    for (const char* v: { "1", "true", "t", "on", "yes", "y"})
228        if (::strncasecmp(var, v, ::strlen(v)) == 0)
229            return true;
230    return false; // false
231}
232};
233
234/// escape char names witout '\'
235static const char cstyleEscapesTable[32] =
236{
237    0, 0, 0, 0, 0, 0, 0, 'a', 'b', 't', 'n', 'v', 'f', 'r', 0, 0,
238    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
239};
240
241std::string CLRX::escapeStringCStyle(size_t strSize, const char* str)
242{
243    std::string out;
244    out.reserve(strSize);
245    bool notFullOctalEscape = false;
246    for (size_t i = 0; i < strSize; i++)
247    {
248        const cxbyte c = str[i];
249        if (c < 0x20 || c > 0x7e || (notFullOctalEscape && c >= 0x30 && c <= 0x37))
250        {
251            if (c < 0x20 && cstyleEscapesTable[c] != 0)
252            {
253                out.push_back('\\');
254                out.push_back(cstyleEscapesTable[c]);
255                notFullOctalEscape = false;
256            }
257            else // otherwise
258            {
259                out.push_back('\\');
260                if ((c>>6) != 0)
261                    out.push_back('0'+(c>>6));
262                if ((c>>3) != 0)
263                    out.push_back('0'+((c>>3)&7));
264                out.push_back('0'+(c&7));
265                // if next character can change octal escape
266                notFullOctalEscape = ((c>>6) == 0);
267            }
268        }
269        else  if (c == '\"')
270        {   // backslash
271            out.push_back('\\');
272            out.push_back('\"');
273            notFullOctalEscape = false;
274        }
275        else  if (c == '\'')
276        {   // backslash
277            out.push_back('\\');
278            out.push_back('\'');
279            notFullOctalEscape = false;
280        }
281        else  if (c == '\\')
282        {   // backslash
283            out.push_back('\\');
284            out.push_back('\\');
285            notFullOctalEscape = false;
286        }
287        else // otherwise normal character
288        {
289            out.push_back(c);
290            notFullOctalEscape = false;
291        }
292    }
293    return out;
294}
295
296size_t CLRX::escapeStringCStyle(size_t strSize, const char* str,
297                 size_t outMaxSize, char* outStr, size_t& outSize)
298{
299    size_t i = 0, d = 0;
300    bool notFullOctalEscape = false;
301    for (i = 0; i < strSize; i++)
302    {
303        const cxbyte c = str[i];
304        if (c < 0x20 || c > 0x7e || (notFullOctalEscape && c >= 0x30 && c <= 0x37))
305        {
306            if (c < 0x20 && cstyleEscapesTable[c] != 0)
307            {
308                if (d+2 >= outMaxSize)
309                    break; // end
310                outStr[d++] = '\\';
311                outStr[d++] = cstyleEscapesTable[c];
312                notFullOctalEscape = false;
313            }
314            else // otherwise
315            {
316                if (d + 2 + ((c>>3) != 0) + ((c>>6) != 0) >= outMaxSize)
317                    break; // end
318                outStr[d++] = '\\';
319                if ((c>>6) != 0)
320                    outStr[d++] = '0'+(c>>6);
321                if ((c>>3) != 0)
322                    outStr[d++] = '0'+((c>>3)&7);
323                outStr[d++] = '0'+(c&7);
324                // if next character can change octal escape
325                notFullOctalEscape = ((c>>6) == 0);
326            }
327        }
328        else  if (c == '\"')
329        {   // backslash
330            if (d+2 >= outMaxSize)
331                break; // end
332            outStr[d++] = '\\';
333            outStr[d++] = '\"';
334            notFullOctalEscape = false;
335        }
336        else  if (c == '\'')
337        {   // backslash
338            if (d+2 >= outMaxSize)
339                break; // end
340            outStr[d++] = '\\';
341            outStr[d++] = '\'';
342            notFullOctalEscape = false;
343        }
344        else  if (c == '\\')
345        {   // backslash
346            if (d+2 >= outMaxSize)
347                break; // end
348            outStr[d++] = '\\';
349            outStr[d++] = '\\';
350            notFullOctalEscape = false;
351        }
352        else // otherwise normal character
353        {
354            if (d+1 >= outMaxSize)
355                break; // end
356            outStr[d++] = c;
357            notFullOctalEscape = false;
358        }
359    }
360    outStr[d] = 0;
361    outSize = d;
362    return i;
363}
364
365bool CLRX::isDirectory(const char* path)
366{
367    struct stat stBuf;
368    errno = 0;
369    if (::stat(path, &stBuf) != 0)
370    {
371        if (errno == ENOENT)
372            throw Exception("File or directory doesn't exists");
373        else if (errno == EACCES)
374            throw Exception("Access to file or directory is not permitted");
375        else
376            throw Exception("Can't determine whether path refers to directory");
377    }
378#ifdef HAVE_WINDOWS
379    return (_S_IFDIR&stBuf.st_mode)!=0;
380#else
381    return S_ISDIR(stBuf.st_mode);
382#endif
383}
384
385/// returns true if file exists
386bool CLRX::isFileExists(const char* path)
387{
388#ifdef HAVE_WINDOWS
389    return GetFileAttributes(path)!=INVALID_FILE_ATTRIBUTES ||
390            GetLastError()!=ERROR_FILE_NOT_FOUND;
391#else
392    return ::access(path, F_OK)==0;
393#endif
394}
395
396Array<cxbyte> CLRX::loadDataFromFile(const char* filename)
397{
398    uint64_t size;
399    if (isDirectory(filename))
400        throw Exception("This is directory!");
401   
402    std::ifstream ifs(filename, std::ios::binary);
403    if (!ifs)
404        throw Exception("Can't open file");
405    ifs.exceptions(std::ifstream::badbit | std::ifstream::failbit);
406   
407    bool seekingIsWorking = true;
408    try
409    { ifs.seekg(0, std::ios::end); /* to end of file */ }
410    catch(const std::exception& ex)
411    {   /* oh, no! this is not regular file */
412        seekingIsWorking = false;
413        ifs.clear();
414    }
415    Array<cxbyte> buf;
416    ifs.exceptions(std::ifstream::badbit); // ignore failbit for read
417    if (seekingIsWorking)
418    {   // just read whole file to memory
419        size = ifs.tellg();
420        if (size > SIZE_MAX)
421            throw Exception("File is too big to load");
422        ifs.seekg(0, std::ios::beg);
423        buf.resize(size);
424        ifs.read((char*)buf.data(), size);
425        if (ifs.gcount() != std::streamsize(size))
426            throw Exception("Can't read whole file");
427    }
428    else
429    {   /* growing, growing... */
430        size_t prevBufSize = 0;
431        size_t readBufSize = 256;
432        buf.resize(readBufSize);
433        while(true)
434        {
435            ifs.read((char*)(buf.data()+prevBufSize), readBufSize-prevBufSize);
436            const size_t readed = ifs.gcount();
437            if (readed < readBufSize-prevBufSize)
438            {   /* final resize */
439                buf.resize(prevBufSize + readed);
440                break;
441            }
442            prevBufSize = readBufSize;
443            readBufSize = prevBufSize+(prevBufSize>>1);
444            buf.resize(readBufSize);
445        }
446    }
447    return buf;
448}
449
450void CLRX::filesystemPath(char* path)
451{
452    while (*path != 0)  // change to native dir separator
453        if (*path == CLRX_ALT_DIR_SEP)
454            *path = CLRX_NATIVE_DIR_SEP;
455}
456
457void CLRX::filesystemPath(std::string& path)
458{
459    for (char& c: path)
460        if (c == CLRX_ALT_DIR_SEP)
461            c = CLRX_NATIVE_DIR_SEP;
462}
463
464std::string CLRX::joinPaths(const std::string& path1, const std::string& path2)
465{
466    std::string outPath = path1;
467    if (path1.back() == CLRX_NATIVE_DIR_SEP)
468    {
469        if (path2.size() >= 1 && path2.front() == CLRX_NATIVE_DIR_SEP)
470            // skip first dir separator
471            outPath.append(path2.begin()+1, path2.end());
472        else
473            outPath += path2;
474    }
475    else
476    {
477        if (path2.size() >= 1 && path2.front() != CLRX_NATIVE_DIR_SEP)
478            outPath.push_back(CLRX_NATIVE_DIR_SEP); // add dir separator
479        outPath += path2;
480    }
481    return outPath;
482}
483
484uint64_t CLRX::getFileTimestamp(const char* filename)
485{
486    struct stat stBuf;
487    errno = 0;
488    if (::stat(filename, &stBuf) != 0)
489    {
490        if (errno == ENOENT)
491            throw Exception("File or directory doesn't exists");
492        else if (errno == EACCES)
493            throw Exception("Access to file or directory is not permitted");
494        else
495            throw Exception("Can't determine whether path refers to directory");
496    }
497#if _POSIX_C_SOURCE>=200800L
498    return stBuf.st_mtim.tv_sec*1000000000ULL + stBuf.st_mtim.tv_nsec;
499#else
500    return stBuf.st_mtime*1000000000ULL;
501#endif
502}
503
504std::string CLRX::getHomeDir()
505{
506#ifndef HAVE_WINDOWS
507    struct passwd pw;
508    long pwbufSize = sysconf(_SC_GETPW_R_SIZE_MAX);
509    if (pwbufSize != -1)
510    {
511        struct passwd* pwres;
512        Array<char> pwbuf(pwbufSize);
513        if (getpwuid_r(getuid(), &pw, pwbuf.data(), pwbufSize, &pwres)==0 &&
514                pwres!=nullptr)
515            return std::string(pwres->pw_dir);
516    }
517#else
518    // requires Windows XP or Windows 2000
519    char path[MAX_PATH];
520    if (SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_PROFILE, nullptr, 0, path)))
521        return std::string(path);
522#endif
523    return "";
524}
525
526void CLRX::makeDir(const char* dirname)
527{
528    errno = 0;
529#ifdef HAVE_WINDOWS
530    int ret = _mkdir(dirname);
531#else
532    // warning this is not thread safe code! (umask)
533    int um = umask(0);
534    umask(um);
535    int ret = ::mkdir(dirname, 0777&~um);
536#endif
537    if (ret!=0)
538    {
539        if (errno == EEXIST)
540            throw Exception("Directory already exists");
541        else if (errno == ENOENT)
542            throw Exception("No such parent directory");
543        else if (errno == EACCES)
544            throw Exception("Access to parent directory is not permitted");
545        else
546            throw Exception("Can't create directory");
547    }
548}
549
550CLRX::Array<cxbyte> CLRX::runExecWithOutput(const char* program, const char** argv)
551{
552#ifndef HAVE_WINDOWS
553    Array<cxbyte> output;
554    errno = 0;
555    int pipefds[2];
556    if (::pipe(pipefds) < 0)
557        throw Exception("Can't create pipe");
558    int fret = fork();
559    if (fret == 0)
560    {   // children
561        if (::close(1)<0)
562            ::exit(-1);
563        if (::dup2(pipefds[1], 1)<0) // redirection to pipe
564            ::exit(-1);
565        ::close(pipefds[0]);
566        ::execvp(program, (char**)argv);
567        ::exit(-1); // not
568    }
569    else if (fret > 0)
570    {   // parent
571        ::close(pipefds[1]);
572        /* growing, growing... */
573        size_t prevBufSize = 0;
574        size_t readBufSize = 256;
575        output.resize(readBufSize);
576        try
577        {
578        while(true)
579        {
580            while (prevBufSize < readBufSize)
581            {
582                ssize_t ret = ::read(pipefds[0], output.data()+prevBufSize,
583                            readBufSize-prevBufSize);
584                if (ret < 0)
585                    throw Exception("Can't read output of running process");
586                prevBufSize += ret;
587                if (ret == 0)
588                    break;
589            }
590            if (prevBufSize < readBufSize)
591            {   /* final resize */
592                output.resize(prevBufSize);
593                break;
594            }
595            prevBufSize = readBufSize;
596            readBufSize = prevBufSize+(prevBufSize>>1);
597            output.resize(readBufSize);
598        }
599        }
600        catch(...)
601        {   // close on error
602            ::waitpid(fret, nullptr, 0);
603            ::close(pipefds[0]);
604            throw;
605        }
606        int status = 0;
607        ::waitpid(fret, &status, 0);
608        ::close(pipefds[0]);
609        if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
610            throw Exception("Process exited abnormally");
611    }
612    else
613        throw Exception("Can't create new process");
614    return output;
615#else
616    throw Exception("Unsupported function");
617#endif
618}
619
620static std::string findFileByEnvPaths(const char* envName, const char* fileName)
621{
622    // find by path
623    const std::string paths = parseEnvVariable<std::string>(envName);
624    for (size_t i = 0; i != std::string::npos; )
625    {
626#ifndef HAVE_WINDOWS
627        size_t nexti = paths.find(':', i);
628#else
629        size_t nexti = paths.find(';', i);
630#endif
631        std::string path;
632        if (nexti != std::string::npos)
633        {   // next
634            path = paths.substr(i, nexti-i);
635            i = nexti+1;
636        }
637        else
638        {   // last
639            path = paths.substr(i);
640            i = std::string::npos;
641        }
642        if (path.empty())
643            continue; // skip empty path
644        std::string filePath = joinPaths(path, fileName);
645        if (isFileExists(filePath.c_str()))
646            return filePath;
647    }
648    return "";
649}
650
651static const char* libAmdOCLPaths[] =
652{
653#ifdef HAVE_LINUX
654#  ifdef HAVE_32BIT
655     "/usr/lib/i386-linux-gnu/amdgpu-pro",
656     "/opt/amdgpu-pro/lib/i386-linux-gnu",
657     "/opt/amdgpu-pro/lib32",
658     "/opt/amdgpu-pro/lib",
659     "/usr/lib/i386-linux-gnu",
660     "/usr/lib32",
661     "/usr/lib"
662#  else
663     "/usr/lib/x86_64-linux-gnu/amdgpu-pro",
664     "/opt/amdgpu-pro/lib/x86_64-linux-gnu",
665     "/usr/lib/x86_64-linux-gnu",
666     "/opt/amdgpu-pro/lib64",
667     "/opt/amdgpu-pro/lib",
668     "/usr/lib64",
669     "/usr/lib"
670#  endif
671#elif defined(HAVE_WINDOWS)
672     "c:\\Windows\\System32"
673#endif
674};
675
676std::string CLRX::findAmdOCL()
677{
678    std::string amdOclPath = parseEnvVariable<std::string>("CLRX_AMDOCL_PATH", "");
679    if (!amdOclPath.empty())
680    {
681        if (isFileExists(amdOclPath.c_str()))
682            return amdOclPath;
683    }
684    else
685    {
686#ifndef HAVE_WINDOWS
687        amdOclPath = findFileByEnvPaths("LD_LIBRARY_PATH", DEFAULT_AMDOCLNAME);
688        if (!amdOclPath.empty())
689            return amdOclPath;
690#endif
691        for (const char* libPath: libAmdOCLPaths)
692        {
693            amdOclPath = joinPaths(libPath, DEFAULT_AMDOCLNAME);
694            if (isFileExists(amdOclPath.c_str()))
695                return amdOclPath;
696        }
697#ifdef HAVE_WINDOWS
698        return findFileByEnvPaths("PATH", DEFAULT_AMDOCLNAME);
699#endif
700    }
701    return "";
702}
703
704#ifndef HAVE_WINDOWS
705static const char* libMesaOCLPaths[] =
706{
707#  ifdef HAVE_32BIT
708     "/usr/lib/i386-linux-gnu",
709     "/usr/lib32",
710     "/usr/lib"
711#  else
712     "/usr/lib/x86_64-linux-gnu",
713     "/usr/lib64",
714     "/usr/lib"
715#  endif
716};
717#endif
718
719std::string CLRX::findMesaOCL()
720{
721#ifndef HAVE_WINDOWS
722    std::string mesaOclPath = parseEnvVariable<std::string>("CLRX_MESAOCL_PATH", "");
723    if (!mesaOclPath.empty())
724    {
725        if (isFileExists(mesaOclPath.c_str()))
726            return mesaOclPath;
727    }
728    else
729    {
730        mesaOclPath = findFileByEnvPaths("LD_LIBRARY_PATH", "libMesaOpenCL.so.1");
731        if (!mesaOclPath.empty())
732            return mesaOclPath;
733        for (const char* libPath: libMesaOCLPaths)
734        {
735            mesaOclPath = joinPaths(libPath, "libMesaOpenCL.so.1");
736            if (isFileExists(mesaOclPath.c_str()))
737                return mesaOclPath;
738        }
739#ifdef HAVE_64BIT
740        if (isFileExists("/usr/lib64/OpenCL/vendors/mesa/libOpenCL.so"))
741            return "/usr/lib64/OpenCL/vendors/mesa/libOpenCL.so";
742        if (isFileExists("/usr/lib/OpenCL/vendors/mesa/libOpenCL.so"))
743            return "/usr/lib/OpenCL/vendors/mesa/libOpenCL.so";
744#else
745        if (isFileExists("/usr/lib32/OpenCL/vendors/mesa/libOpenCL.so"))
746            return "/usr/lib32/OpenCL/vendors/mesa/libOpenCL.so";
747        if (isFileExists("/usr/lib/OpenCL/vendors/mesa/libOpenCL.so"))
748            return "/usr/lib/OpenCL/vendors/mesa/libOpenCL.so";
749#endif
750    }
751#endif
752    return "";
753}
754
755std::string CLRX::findLLVMConfig()
756{
757    std::string llvmConfigPath = parseEnvVariable<std::string>("CLRX_LLVMCONFIG_PATH", "");
758    if (!llvmConfigPath.empty())
759    {
760        if (isFileExists(llvmConfigPath.c_str()))
761            return llvmConfigPath;
762        return "";
763    }
764    else
765    {
766        // find by path
767        llvmConfigPath = findFileByEnvPaths("PATH", "llvm-config");
768        if (!llvmConfigPath.empty())
769            return llvmConfigPath;
770#ifndef HAVE_WINDOWS
771        if (isFileExists("/usr/bin/llvm-config"))
772            return "/usr/bin/llvm-config";
773#endif
774    }
775    return "";
776}
Note: See TracBrowser for help on using the repository browser.