Skip to content

Commit

Permalink
RTC include directory detection. (#387)
Browse files Browse the repository at this point in the history
* RTC will now attempt to auto find the include dir if variable is not set.
* CMake configure step auto generates a version file which is used for ensuring header version matches library build version.
(Might wish to make the version file generation behaviour different in future if this ends up too aggressive)
Partially addresses #253 
Co-authored-by: Peter Heywood <peethwd@gmail.com>
  • Loading branch information
Robadob authored Oct 14, 2020
1 parent 5f6ee19 commit 168c9e5
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 7 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
*.json
*.bin

# dynamically generated version file
include/flamegpu/version.h

# GoogleTest directories (handled by CMake)
googletest-build/
googletest-download/
Expand Down
62 changes: 62 additions & 0 deletions cmake/common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ if(Jitify_FOUND)
set(FLAMEGPU_DEPENDENCY_INCLUDE_DIRECTORIES ${FLAMEGPU_DEPENDENCY_INCLUDE_DIRECTORIES} "${Jitify_INCLUDE_DIRS}")
endif()

# If gcc, need to add linker flag for std::experimental::filesystem pre c++17
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(FLAMEGPU_DEPENDENCY_LINK_LIBRARIES ${FLAMEGPU_DEPENDENCY_LINK_LIBRARIES} "-lstdc++fs")
endif()

# Logging for jitify compilation
set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -DJITIFY_PRINT_LOG")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DJITIFY_PRINT_LOG")
Expand Down Expand Up @@ -401,6 +406,9 @@ endfunction()

# Function to mask some of the flag setting for the static library
function(add_flamegpu_library NAME SRC FLAMEGPU_ROOT)
# Generate version file
GET_COMMIT_HASH()

# Define which source files are required for the target executable
add_library(${NAME} STATIC ${SRC})

Expand Down Expand Up @@ -498,3 +506,57 @@ macro(CMAKE_SET_TARGET_FOLDER tgt folder)
set_property(GLOBAL PROPERTY USE_FOLDERS OFF)
endif()
endmacro()

#-----------------------------------------------------------------------
# Generate files that act as informal version numbers
# ${CMAKE_CURRENT_BINARY_DIR}/short_hash.txt - File only contains git short hash for use by CMake
# ${FLAMEGPU_ROOT}/include/flamegpu/version.h - Programatically accessible version
#
# Based on https://cmake.org/pipermail/cmake/2018-October/068388.html
#-----------------------------------------------------------------------
macro(GET_COMMIT_HASH)
# If git changes, we reconfigure
# This is a very aggressive version
# Might be better to simply make generation of the file a pre-build script
# That would be cheaper than re-configure
set_property(
DIRECTORY
APPEND
PROPERTY CMAKE_CONFIGURE_DEPENDS
"${FLAMEGPU_ROOT}/.git/index"
)
set(SHORT_HASH_FILE ${CMAKE_CURRENT_BINARY_DIR}/short_hash.txt)
find_package(Git)
if(Git_FOUND)
execute_process(
COMMAND
${GIT_EXECUTABLE} rev-parse --short HEAD
WORKING_DIRECTORY
${FLAMEGPU_ROOT}
RESULT_VARIABLE
SHORT_HASH_RESULT
OUTPUT_VARIABLE
SHORT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE)
else()
set(SHORT_HASH "GitHash") # Placeholder, though its unlikely to be required
endif()

file(WRITE ${SHORT_HASH_FILE} ${SHORT_HASH})
# Also create version.h
configure_file(${FLAMEGPU_ROOT}/cmake/version.h ${FLAMEGPU_ROOT}/include/flamegpu/version.h)

# The trick here is to make sure short_hash.txt is listed as a byproduct
add_custom_target(
git_short_hash
BYPRODUCTS
${SHORT_HASH_FILE}
COMMAND
${CMAKE_COMMAND}
"-DSHORT_HASH_FILE=${SHORT_HASH_FILE}"
"-P" "${CMAKE_CURRENT_LIST_FILE}"
COMMENT
"Re-checking short hash..."
VERBATIM
USES_TERMINAL)
endmacro()
15 changes: 15 additions & 0 deletions cmake/version.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**${SHORT_HASH}
* This file is automatically generated at CMake configure time, do not modify
*/
#ifndef INCLUDE_FLAMEGPU_VERSION_H_
#define INCLUDE_FLAMEGPU_VERSION_H_

#include <string>

namespace flamegpu_internal {
std::string getCommitHash() {
return "${SHORT_HASH}";
}
} // namespace flamegpu_internal

#endif // INCLUDE_FLAMEGPU_VERSION_H_
4 changes: 4 additions & 0 deletions include/flamegpu/exception/FGPUException.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,5 +411,9 @@ DERIVED_FGPUException(ExpiredWeakPtr, "Unable to convert weak pointer to shared
* Defines an error reported from cuda device code (agent functions and agent function conditions)
*/
DERIVED_FGPUException(DeviceError, "Error reported from device code");
/**
* Defines an error reported when versions do not match
*/
DERIVED_FGPUException(VersionMismatch, "Versions do not match");

#endif // INCLUDE_FLAMEGPU_EXCEPTION_FGPUEXCEPTION_H_
6 changes: 4 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@ endif()

# Specify source files for the static library
# Can't do this automatically, as CMake wouldn't know when to regen (as CMakeLists.txt would be unchanged)
# version.h is automatically generated so does not exist prior to configure time
SET(SRC_INCLUDE
${FLAMEGPU_ROOT}/include/flamegpu/version.h
${FLAMEGPU_ROOT}/include/flamegpu/defines.h
${FLAMEGPU_ROOT}/include/flamegpu/flame_api.h
${FLAMEGPU_ROOT}/include/flamegpu/io/statereader.h
${FLAMEGPU_ROOT}/include/flamegpu/io/statewriter.h
${FLAMEGPU_ROOT}/include/flamegpu/io/jsonReader.h
Expand All @@ -91,7 +95,6 @@ SET(SRC_INCLUDE
${FLAMEGPU_ROOT}/include/flamegpu/pop/AgentPopulation.h
${FLAMEGPU_ROOT}/include/flamegpu/pop/MemoryVector.h
${FLAMEGPU_ROOT}/include/flamegpu/pop/AgentStateMemory.h
${FLAMEGPU_ROOT}/include/flamegpu/defines.h
${FLAMEGPU_ROOT}/include/flamegpu/gpu/CUDAScanCompaction.h
${FLAMEGPU_ROOT}/include/flamegpu/gpu/CUDAErrorChecking.h
${FLAMEGPU_ROOT}/include/flamegpu/gpu/CUDAMessageList.h
Expand All @@ -102,7 +105,6 @@ SET(SRC_INCLUDE
${FLAMEGPU_ROOT}/include/flamegpu/gpu/CUDAFatAgent.h
${FLAMEGPU_ROOT}/include/flamegpu/gpu/CUDAFatAgentStateList.h
${FLAMEGPU_ROOT}/include/flamegpu/gpu/CUDAScatter.h
${FLAMEGPU_ROOT}/include/flamegpu/flame_api.h
${FLAMEGPU_ROOT}/include/flamegpu/sim/AgentInterface.h
${FLAMEGPU_ROOT}/include/flamegpu/sim/Simulation.h
${FLAMEGPU_ROOT}/include/flamegpu/runtime/AgentFunction.h
Expand Down
67 changes: 62 additions & 5 deletions src/flamegpu/gpu/CUDAAgent.cu
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@
#include <cuda_runtime.h>
#include <device_launch_parameters.h>

#include <iostream>
#include <fstream>
#include <string>
// If MSVC earlier than VS 2019
#if defined(_MSC_VER) && _MSC_VER < 1920
#include <filesystem>
using std::tr2::sys::exists;
using std::tr2::sys::path;
#else
// VS2019 requires this macro, as building pre c++17 cant use std::filesystem
#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
#include <experimental/filesystem>
using std::experimental::filesystem::v1::exists;
using std::experimental::filesystem::v1::path;
#endif

#include "flamegpu/version.h"
#include "flamegpu/gpu/CUDAFatAgent.h"
#include "flamegpu/gpu/CUDAAgentStateList.h"
#include "flamegpu/gpu/CUDAErrorChecking.h"
Expand Down Expand Up @@ -419,11 +436,51 @@ void CUDAAgent::clearFunctionCondition(const std::string &state) {

void CUDAAgent::addInstantitateRTCFunction(jitify::JitCache &kernel_cache, const AgentFunctionData& func, bool function_condition) {
// get header location for fgpu
const char* env_inc_fgp2 = std::getenv("FLAMEGPU2_INC_DIR");
if (!env_inc_fgp2) {
THROW InvalidAgentFunc("Error compiling runtime agent function ('%s'): FLAMEGPU2_INC_DIR environment variable does not exist, "
"in CUDAAgent::addInstantitateRTCFunction().",
func.name.c_str());
static std::string env_inc_fgp2 = std::getenv("FLAMEGPU2_INC_DIR") ? std::getenv("FLAMEGPU2_INC_DIR") : "";
static bool header_version_confirmed = false;
if (env_inc_fgp2.empty()) {
// Var is not set, attempt to use default arrangement
path test_include("");
// Try 5 levels of directory, to see if we can find flame_api.h
for (int i = 0; i < 5; ++i) {
path check_file = test_include;
check_file/= "include/flamegpu/version.h";
if (exists(check_file)) {
test_include/= "include";
env_inc_fgp2 = test_include.string();
break;
}
// Go up a level for next iteration
test_include/= "..";
}
if (env_inc_fgp2.empty()) {
THROW InvalidAgentFunc("Error compiling runtime agent function ('%s'): Unable to automatically determine include directory and FLAMEGPU2_INC_DIR environment variable does not exist, "
"in CUDAAgent::addInstantitateRTCFunction().",
func.name.c_str());
}
}

if (!header_version_confirmed) {
std::string fileHash;
// Open version.h
path version_file = env_inc_fgp2;
version_file/= "flamegpu/version.h";
std::ifstream vFile(version_file);
if (vFile.is_open()) {
// Read the first line
std::string line;
if (getline(vFile, line)) {
// If characters 3-9 match programatic hash we have success, else fail
fileHash = line.substr(3, 7);
}
vFile.close();
}
if (fileHash == flamegpu_internal::getCommitHash()) {
header_version_confirmed = true;
} else {
THROW VersionMismatch("RTC header version (%s) does not match version flamegpu2 library was built with (%s). Set the environment variable FLAMEGPU2_INC_DIR to the correct include directory.\n",
fileHash.c_str(), flamegpu_internal::getCommitHash().c_str());
}
}

// get the cuda path
Expand Down

0 comments on commit 168c9e5

Please sign in to comment.