Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Executable folder utilities #77

Merged
merged 15 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ project(OpenCL-SDK
)

include(CMakeDependentOption)
option(OPENCL_SDK_BUILD_SAMPLES "Build sample code" ON)
option(OPENCL_SDK_BUILD_UTILITY_LIBRARIES "Build utility libraries" ON)
cmake_dependent_option(OPENCL_SDK_BUILD_SAMPLES "Build sample code" ON OPENCL_SDK_BUILD_UTILITY_LIBRARIES OFF)
cmake_dependent_option(OPENCL_SDK_BUILD_OPENGL_SAMPLES "Build OpenCL-OpenGL interop sample code" ON OPENCL_SDK_BUILD_SAMPLES OFF)
cmake_dependent_option(OPENCL_SDK_TEST_SAMPLES "Add CTest to samples (where applicable)" ON OPENCL_SDK_BUILD_SAMPLES OFF)

Expand All @@ -47,8 +48,9 @@ list(APPEND CMAKE_MODULE_PATH
${PROJECT_SOURCE_DIR}/cmake/Modules
)
include(Dependencies)

add_subdirectory(lib)
if(OPENCL_SDK_BUILD_UTILITY_LIBRARIES)
add_subdirectory(lib)
endif()
if(OPENCL_SDK_BUILD_SAMPLES)
add_subdirectory(samples)
endif()
Expand Down
7 changes: 7 additions & 0 deletions cmake/Dependencies.cmake
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
if(OPENCL_SDK_BUILD_UTILITY_LIBRARIES)
foreach(DEP IN ITEMS whereami)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/Dependencies/${DEP}")
include(${DEP})
endforeach()
endif()

if(OPENCL_SDK_BUILD_SAMPLES)
foreach(DEP IN ITEMS cargs TCLAP Stb)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/Dependencies/${DEP}")
Expand Down
15 changes: 15 additions & 0 deletions cmake/Dependencies/whereami/whereami.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.11)
include(FetchContent)
FetchContent_Declare(
whereami-external
GIT_REPOSITORY https://github.com/gpakosz/whereami.git
GIT_TAG ba364cd54fd431c76c045393b6522b4bff547f50 # master @ 2023.04.20.
)
FetchContent_MakeAvailable(whereami-external)
add_library(whereami IMPORTED INTERFACE)
target_include_directories(whereami
INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/_deps/whereami-external-src/src"
)
target_sources(whereami
INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/_deps/whereami-external-src/src/whereami.c"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need this because you want to cope with old CMake?
Or just because whereami does not use modern CMake features.
You can clarify my brain by adding comments in the CMake configuration. :-)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing this because whereami is lacking CMake support completely.

)
2 changes: 2 additions & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ foreach(UTIL_LIB_NAME IN ITEMS Utils UtilsCpp)
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
)
target_link_libraries(${UTIL_LIB_TARGET}
PRIVATE
whereami
PUBLIC
${UTIL_LIB_DEPS}
OpenCL::OpenCL
Expand Down
95 changes: 95 additions & 0 deletions lib/Utils.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The OpenCL Utility Library provides both C and C++ bindings with near feature pa
- [Context](#context-utilities)
- [Event](#event-utilities)
- [Error](#error-handling-utilities)
- [File](#file-utilities)

### Platform utilities

Expand Down Expand Up @@ -119,3 +120,97 @@ public:
};
```
This type is used as the exception type thrown by utilities when an error occurs and the compiling code defines `CL_HPP_ENABLE_EXCEPTIONS`

### File utilities

```c
char* cl_util_read_text_file(
const char* const filename,
size_t* const length,
cl_int* const error);
```

```c++
std::string cl::util::read_text_file(
const char* const filename,
cl_int* const error = nullptr);
```

These functions read a text file into memory, where `filename` is evaluated relative to the current working directory. The C-version contains a terminating null and takes an optional pointer to `length` by which the length my be returned, potentially saving a subsequent call to `strlen`. The function hands ownership of the allocated storage to the caller.

```c
unsigned char* cl_util_read_binary_file(
const char* const filename,
size_t* const length,
cl_int* const error);
```

```c++
std::vector<unsigned char> read_binary_file(
const char* const filename,
cl_int* const error = nullptr);
```

These functions read a binary file into memory, where `filename` is evaluated relative to the current working directory. The C-version takes an optional pointer to `length` by which the length my be returned. Because it's binary data, it is _not_ null-terminated, therefore highly recommended to take it's size. The returned types align with OpenCL APIs taking binaries as input. The function hands ownership of the allocated storage to the caller.

```c
cl_program cl_util_read_binaries(
const cl_context context,
const cl_device_id* const devices,
const cl_uint num_devices,
const char* const program_file_name,
cl_int* const error
);
```

```c++
Program::Binaries read_binary_files(
const std::vector<cl::Device>& devices,
const char* const program_file_name,
cl_int* const error = nullptr);
```

These functions read a set of binary files into memory. `program_file_name` is a pattern that will be completed for every input device using the `"(program_file_name)_(name of device).bin"` pattern. If any of the files are not found, the function fails.

```c
cl_int cl_util_write_binaries(
const cl_program program,
const char* const program_file_name);
```

```c++
write_binaries(
const cl::Program::Binaries& binaries,
const std::vector<cl::Device>& devices,
const char* const program_file_name);
```

These functions will write all device binaries of a program to persistent storage. `program_file_name` is a pattern that will be completed for every input device using the `"(program_file_name)_(name of device).bin"` pattern.

```c
cl_int cl_util_executable_folder(
char* filename,
size_t* const length);
```

```c++
std::string executable_folder(
cl_int* const error = nullptr);
```

These functions return the path to the folder containing the currently running executable. It is typically useful to find assets which are stored uniformly in a program's build and install tree. The C-version contains a terminating null and takes an optional pointer to `length` by which the length my be returned, potentially saving a subsequent call to `strlen`.

```c
char* cl_util_read_exe_relative_text_file(
const char* const rel_path,
size_t* const length,
cl_int* const error);
```

```c++
std::string read_exe_relative_text_file(
const char* const filename,
cl_int* const error = nullptr);
```

These functions read a text file into memory, where `filename` is evaluated relative to the executable currently running. The C-version contains a terminating null and takes an optional pointer to `length` by which the length will be returned, potentially saving a subsequent call to `strlen`. The function hands ownership of the allocated storage to the caller.
13 changes: 13 additions & 0 deletions lib/include/CL/Utils/File.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,16 @@ cl_program cl_util_read_binaries(const cl_context context,
const cl_uint num_devices,
const char* const program_file_name,
cl_int* const error);

// returns the folder containing the running executable
UTILS_EXPORT
cl_int cl_util_executable_folder(char* filename, size_t* const length);

// read all the text file contents securely in ANSI C89
// return pointer to C-string with file contents
// interprets filename relative to the folder containing
// the running executable
UTILS_EXPORT
char* cl_util_read_exe_relative_text_file(const char* const rel_path,
size_t* const length,
cl_int* const error);
16 changes: 11 additions & 5 deletions lib/include/CL/Utils/File.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,24 @@ namespace cl {
namespace util {

std::string UTILSCPP_EXPORT read_text_file(const char* const filename,
cl_int* const error);
cl_int* const error = nullptr);

std::vector<unsigned char> UTILSCPP_EXPORT
read_binary_file(const char* const filename, cl_int* const error);
read_binary_file(const char* const filename, cl_int* const error = nullptr);

Program::Binaries UTILSCPP_EXPORT
read_binary_files(const std::vector<cl::Device>& devices,
const char* const program_file_name, cl_int* const error);
Program::Binaries UTILSCPP_EXPORT read_binary_files(
const std::vector<cl::Device>& devices,
const char* const program_file_name, cl_int* const error = nullptr);

cl_int UTILSCPP_EXPORT
write_binaries(const cl::Program::Binaries& binaries,
const std::vector<cl::Device>& devices,
const char* const program_file_name);

std::string UTILSCPP_EXPORT
executable_folder(cl_int* const error = nullptr);

std::string UTILSCPP_EXPORT read_exe_relative_text_file(
const char* const filename, cl_int* const error = nullptr);
}
}
76 changes: 76 additions & 0 deletions lib/src/Utils/File.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#include <stdio.h> // fopen, ferror, fread, fclose
#include <string.h> // memset

// whereami includes
#include <whereami.h>

// read all the text file contents securely in ANSI C89
// return pointer to C-string with file contents
// can handle streams with no known size and no support for fseek
Expand Down Expand Up @@ -329,3 +332,76 @@ cl_program cl_util_read_binaries(const cl_context context,
if (error != NULL) *error = err;
return program;
}

UTILS_EXPORT
cl_int cl_util_executable_folder(char *const filename, size_t *const length)
{
cl_int err = CL_SUCCESS;
int wai_length, wai_dirname_length = 0;
char *wai_filename = NULL;

#define IF_ERR(func, error_type, label) \
do \
{ \
if (func) \
{ \
err = error_type; \
goto label; \
} \
} while (0)

wai_length = wai_getExecutablePath(NULL, 0, NULL);
IF_ERR(wai_length == -1, CL_UTIL_FILE_OPERATION_ERROR, end);
MEM_CHECK(wai_filename = (char *)malloc(wai_length), err, end);
IF_ERR(wai_getExecutablePath(wai_filename, wai_length, &wai_dirname_length)
== -1,
CL_UTIL_FILE_OPERATION_ERROR, end);

if (length != NULL)
{
*length = (int)wai_dirname_length + 1;
}

if (filename != NULL)
{
memmove(filename, wai_filename, wai_dirname_length);
filename[wai_dirname_length] = '\0';
}

end:
free(wai_filename);

return err;
}

// read all the text file contents securely in ANSI C89
// return pointer to C-string with file contents
// interprets filename relative to the folder containing
// the running executable
UTILS_EXPORT
char *cl_util_read_exe_relative_text_file(const char *const rel_path,
size_t *const length,
cl_int *const error)
{
char *result = NULL;
size_t result_size = 0;
char *abs_path = NULL;
cl_int err = CL_SUCCESS;
size_t exe_folder_length;
OCLERROR_RET(cl_util_executable_folder(NULL, &exe_folder_length), err, end);
MEM_CHECK(abs_path = (char *)malloc(exe_folder_length
+ strlen(rel_path) + 1),
err, end);
OCLERROR_RET(cl_util_executable_folder(abs_path, NULL), err, end);
strcat(strcat(abs_path, "/"), rel_path);
OCLERROR_PAR(result = cl_util_read_text_file(abs_path, &result_size, &err),
err, end);

if (length != NULL) *length = result_size;

if (error != NULL) *error = err;
end:
free(abs_path);

return result;
}
54 changes: 52 additions & 2 deletions lib/src/Utils/File.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#include <algorithm>
#include <iostream>

// whereami includes
#include <whereami.h>

std::string cl::util::read_text_file(const char* const filename,
cl_int* const error)
{
Expand All @@ -29,7 +32,8 @@ std::string cl::util::read_text_file(const char* const filename,
}
else
{
detail::errHandler(CL_UTIL_FILE_OPERATION_ERROR, error, "No file!");
detail::errHandler(CL_UTIL_FILE_OPERATION_ERROR, error,
(std::string("Unable to read ") + filename).c_str());
return std::string();
}
}
Expand All @@ -54,7 +58,8 @@ cl::util::read_binary_file(const char* const filename, cl_int* const error)
}
else
{
detail::errHandler(CL_UTIL_FILE_OPERATION_ERROR, error, "No file!");
detail::errHandler(CL_UTIL_FILE_OPERATION_ERROR, error,
(std::string("Unable to read ") + filename).c_str());
return std::vector<unsigned char>();
}
}
Expand Down Expand Up @@ -120,3 +125,48 @@ cl_int cl::util::write_binaries(const cl::Program::Binaries& binaries,
return error;
}
}

std::string cl::util::executable_folder(cl_int* const error)
{
int wai_length = wai_getExecutablePath(NULL, 0, NULL);
if (wai_length == -1)
{
detail::errHandler(CL_UTIL_FILE_OPERATION_ERROR, error,
"Unable to query executable path length!");
return "";
}
std::string wai_filename(wai_length, '\0');
int wai_dirname_length = -1;
wai_length = wai_getExecutablePath(&wai_filename.front(), wai_length,
&wai_dirname_length);
if (wai_length == -1 || wai_dirname_length == -1)
{
detail::errHandler(CL_UTIL_FILE_OPERATION_ERROR, error,
"Unable to query executable path or folder length!");
return "";
}

return wai_filename.substr(0, wai_dirname_length);
}

std::string cl::util::read_exe_relative_text_file(const char* const filename,
cl_int* const error)
{
cl_int err = CL_SUCCESS;
std::string exe_folder = executable_folder(&err);
if (err != CL_SUCCESS)
{
detail::errHandler(CL_UTIL_FILE_OPERATION_ERROR, error,
"Failed to query exe folder!");
return "";
}
std::string result =
read_text_file((exe_folder + "/" + filename).c_str(), &err);
if (err != CL_SUCCESS)
{
detail::errHandler(CL_UTIL_FILE_OPERATION_ERROR, error,
"Unable to read file!");
return "";
}
return result;
}
5 changes: 2 additions & 3 deletions samples/core/binaries/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,12 @@ int main(int argc, char *argv[])

if (error != CL_SUCCESS)
{ // if binary not present, compile and save
const char *kernel_location = "./Collatz.cl";
char *kernel = NULL;
size_t program_size = 0;
char *options = NULL;

OCLERROR_PAR(kernel = cl_util_read_text_file(kernel_location,
&program_size, &error),
OCLERROR_PAR(kernel = cl_util_read_exe_relative_text_file(
"Collatz.cl", &program_size, &error),
error, cont);
printf("OpenCL file red... ");

Expand Down
Loading
Loading