Skip to content

Commit

Permalink
Move plProduct info into a generated file.
Browse files Browse the repository at this point in the history
This has a few benefits:
- Changing an aspect of the product rebuilds only plProduct.cpp instead
  of the entire CoreLib project.
- We can now include more information, like the git tag/ref and build
  time. This is useful because the build ID is usually always 918 and is
  more to-do with the client/server handshake than an actual build
  identifier.

If working on a large changeset, you can bypass overhead from this by
setting `-DPRODUCT_EMBED_BUILD_INFO=OFF`.
  • Loading branch information
Hoikas committed Mar 11, 2021
1 parent a66a45f commit a472397
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 38 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Expand Up @@ -22,6 +22,8 @@ set(PRODUCT_SHORT_NAME "UruLive" CACHE STRING "Product Short Name")
set(PRODUCT_LONG_NAME "Uru Live" CACHE STRING "Product Long Name")
set(PRODUCT_UUID "ea489821-6c35-4bd0-9dae-bb17c585e680"
CACHE STRING "Product UUID")
option(PRODUCT_EMBED_BUILD_INFO "Embed build revision information into plProduct" ON)
cmake_dependent_option(PRODUCT_EMBED_BUILD_TIME "Embed build time into plProduct" ON [[PRODUCT_EMBED_BUILD_INFO]] OFF)

# HeadSpin Configuration
if(WIN32 AND NOT CYGWIN)
Expand Down
35 changes: 26 additions & 9 deletions Sources/Plasma/CoreLib/CMakeLists.txt
@@ -1,11 +1,3 @@
add_definitions(-DPRODUCT_BRANCH_ID=${PRODUCT_BRANCH_ID})
add_definitions(-DPRODUCT_BUILD_ID=${PRODUCT_BUILD_ID})
add_definitions(-DPRODUCT_BUILD_TYPE=${PRODUCT_BUILD_TYPE})
add_definitions(-DPRODUCT_CORE_NAME="${PRODUCT_CORE_NAME}")
add_definitions(-DPRODUCT_SHORT_NAME="${PRODUCT_SHORT_NAME}")
add_definitions(-DPRODUCT_LONG_NAME="${PRODUCT_LONG_NAME}")
add_definitions(-DPRODUCT_UUID="${PRODUCT_UUID}")

set(CoreLib_SOURCES
HeadSpin.cpp
hsBitVector.cpp
Expand Down Expand Up @@ -95,7 +87,32 @@ target_link_libraries(
Threads::Threads
$<$<AND:$<CONFIG:Debug>,$<BOOL:${USE_VLD}>>:VLD::VLD>
)
target_include_directories(CoreLib PUBLIC ${CMAKE_CURRENT_LIST_DIR})
target_include_directories(
CoreLib
PUBLIC
${CMAKE_CURRENT_LIST_DIR}
PRIVATE
${CMAKE_CURRENT_BINARY_DIR} # For hsBuildInfo.inl
)

source_group("Source Files" FILES ${CoreLib_SOURCES})
source_group("Header Files" FILES ${CoreLib_HEADERS})

set(BUILD_INFO_FILE "${CMAKE_CURRENT_BINARY_DIR}/hsBuildInfo.inl")
set(BUILD_INFO_COMMAND ${CMAKE_COMMAND}
-DPRODUCT_BRANCH_ID=${PRODUCT_BRANCH_ID}
-DPRODUCT_BUILD_ID=${PRODUCT_BUILD_ID}
-DPRODUCT_BUILD_TYPE=${PRODUCT_BUILD_TYPE}
-DPRODUCT_CORE_NAME=${PRODUCT_CORE_NAME}
-DPRODUCT_SHORT_NAME=${PRODUCT_SHORT_NAME}
-DPRODUCT_LONG_NAME=${PRODUCT_LONG_NAME}
-DPRODUCT_UUID=${PRODUCT_UUID}
-DPRODUCT_EMBED_BUILD_INFO=${PRODUCT_EMBED_BUILD_INFO}
-DPRODUCT_EMBED_BUILD_TIME=${PRODUCT_EMBED_BUILD_TIME}
-P "${CMAKE_MODULE_PATH}/BuildInfo.cmake"
)
add_custom_target(pcBuildInfo
COMMAND ${BUILD_INFO_COMMAND}
BYPRODUCTS "${BUILD_INFO_FILE}"
)
add_dependencies(CoreLib pcBuildInfo)
1 change: 1 addition & 0 deletions Sources/Plasma/CoreLib/_CoreLibPch.h
Expand Up @@ -53,6 +53,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include <functional>
#include <limits.h>
#include <memory>
#include <string_view>
#include <type_traits>
#include <vector>

Expand Down
45 changes: 20 additions & 25 deletions Sources/Plasma/CoreLib/plProduct.cpp
Expand Up @@ -43,36 +43,31 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plProduct.h"

#include "HeadSpin.h"

#include <string_theory/format>
#include <string_view>

static_assert(PRODUCT_BUILD_ID > 0, "Build ID cannot be zero");
static_assert(PRODUCT_BUILD_TYPE > 0, "Build Type cannot be zero");
static_assert(PRODUCT_BRANCH_ID > 0, "Branch ID cannot be zero");
#include "hsBuildInfo.inl"

uint32_t plProduct::BuildId() { return PRODUCT_BUILD_ID; }
uint32_t plProduct::BuildType() { return PRODUCT_BUILD_TYPE; }
uint32_t plProduct::BranchId() { return PRODUCT_BRANCH_ID; }

ST::string plProduct::CoreName()
{
static ST::string _coreName = ST_LITERAL(PRODUCT_CORE_NAME);
return _coreName;
}
static_assert(plProduct::PRODUCT_BUILD_ID > 0, "Build ID cannot be zero");
static_assert(plProduct::PRODUCT_BUILD_TYPE > 0, "Build Type cannot be zero");
static_assert(plProduct::PRODUCT_BRANCH_ID > 0, "Branch ID cannot be zero");
static_assert(!plProduct::PRODUCT_UUID.empty(), "UUID should not be empty");

ST::string plProduct::ShortName()
{
static ST::string _shortName = ST_LITERAL(PRODUCT_SHORT_NAME);
return _shortName;
}
ST::string plProduct::Rev() { return GIT_REV; }
ST::string plProduct::Tag() { return GIT_TAG; }

ST::string plProduct::LongName()
{
static ST::string _longName = ST_LITERAL(PRODUCT_LONG_NAME);
return _longName;
}
ST::string plProduct::BuildDate() { return VOLATILE_BUILD_DATE; }
ST::string plProduct::BuildTime() { return VOLATILE_BUILD_TIME; }

const char *plProduct::UUID() { return PRODUCT_UUID; }
uint32_t plProduct::BuildId() { return PRODUCT_BUILD_ID; }
uint32_t plProduct::BuildType() { return PRODUCT_BUILD_TYPE; }
uint32_t plProduct::BranchId() { return PRODUCT_BRANCH_ID; }

ST::string plProduct::CoreName() { return PRODUCT_CORE_NAME; }
ST::string plProduct::ShortName() { return PRODUCT_SHORT_NAME; }
ST::string plProduct::LongName() { return PRODUCT_LONG_NAME; }
const char *plProduct::UUID() { return PRODUCT_UUID.data(); }

#ifdef PLASMA_EXTERNAL_RELEASE
# define RELEASE_ACCESS "External"
Expand All @@ -89,7 +84,7 @@ const char *plProduct::UUID() { return PRODUCT_UUID; }
ST::string plProduct::ProductString()
{
static ST::string _cache = ST::format(
"{}.{}.{} - " RELEASE_ACCESS "." RELEASE_TYPE,
CoreName(), BranchId(), BuildId());
"{}.{}.{} - {} - " RELEASE_ACCESS "." RELEASE_TYPE,
CoreName(), BranchId(), BuildId(), Tag());
return _cache;
}
20 changes: 16 additions & 4 deletions Sources/Plasma/CoreLib/plProduct.h
Expand Up @@ -44,10 +44,22 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com

namespace ST { class string; }

// Note: These are all implemented in plProduct.cpp, so that only CoreLib
// has to get the product product ID compiler flags passed in.
// Note: These are all implemented in plProduct.cpp, so that only one file
// has to include the product definitions.
namespace plProduct
{
/** \returns The commit SHA of the build. */
ST::string Rev();

/** \returns The name of the tag matching this commit, or the SHA if none. */
ST::string Tag();

/** \returns The date of this build. */
ST::string BuildDate();

/** \returns The time of this build. */
ST::string BuildTime();

uint32_t BuildId();
uint32_t BuildType();
uint32_t BranchId();
Expand All @@ -58,8 +70,8 @@ namespace plProduct

const char *UUID();

/** Returns: "<ProductCoreName>.<BranchId>.<BuildId> - <External|Internal>.<Debug|Release>"
* Example: "Uru.3.204 - External.Release"
/** Returns: "<ProductCoreName>.<BranchId>.<BuildId> - <GitTag> - <External|Internal>.<Debug|Release>"
* Example: "Uru.3.204 - v3.204 - External.Release"
*/
ST::string ProductString();
}
114 changes: 114 additions & 0 deletions cmake/BuildInfo.cmake
@@ -0,0 +1,114 @@
cmake_minimum_required(VERSION 3.14)

# These values indicate "something went wrong"
set(PRODUCT_BRANCH_ID "0" CACHE STRING "Branch ID")
set(PRODUCT_BUILD_ID "0" CACHE STRING "Build ID")
set(PRODUCT_BUILD_TYPE "0" CACHE STRING "Build Type")

if(PRODUCT_EMBED_BUILD_INFO)
find_package(Git QUIET)
if(Git_FOUND)
execute_process(
COMMAND ${GIT_EXECUTABLE} log --pretty=format:%H -n 1
OUTPUT_VARIABLE GIT_REV
ERROR_QUIET
)
execute_process(
COMMAND git diff --exit-code
OUTPUT_VARIABLE GIT_DIFF_CONTENTS
RESULT_VARIABLE GIT_DIFF
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
execute_process(
COMMAND git describe --exact-match --tags
OUTPUT_VARIABLE GIT_TAG
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
string(REGEX REPLACE "[\r\n]" " " GIT_TAG "${GIT_TAG}")

if(NOT GIT_TAG)
execute_process(
COMMAND ${GIT_EXECUTABLE} log --pretty=format:%h -n 1
OUTPUT_VARIABLE GIT_TAG
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
endif()
if(GIT_DIFF EQUAL 1)
string(APPEND GIT_REV "_dirty")
string(APPEND GIT_TAG "_dirty")
endif()
endif()
endif()

if(NOT GIT_REV)
set(GIT_REV "untracked")
endif()
if(NOT GIT_TAG)
set(GIT_TAG ${GIT_REV})
endif()

if(PRODUCT_EMBED_BUILD_TIME)
# Include the hash of the diff to ensure that non-commit changes trigger a build-time update.
string(SHA256 CURRENT_DIFF_HASH "${GIT_DIFF_CONTENTS}")

if(WIN32)
execute_process(
COMMAND powershell -Command "Get-Date -UFormat +%Y-%m-%d"
OUTPUT_VARIABLE BUILD_DATE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND powershell -Command "Get-Date -UFormat +%H:%M%Z"
OUTPUT_VARIABLE BUILD_TIME
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Force UTC offset to four digits instead of two
string(REGEX REPLACE [[(-|\+)([0-9][0-9])$]] [[\1\200]] BUILD_TIME "${BUILD_TIME}")
else()
execute_process(
COMMAND date +%Y-%m-%d
OUTPUT_VARIABLE BUILD_DATE
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND date +%H:%M%z
OUTPUT_VARIABLE BUILD_TIME
OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()
else()
set(CURRENT_DIFF_HASH "untracked")
set(BUILD_DATE "untracked")
set(BUILD_TIME "untracked")
endif()

# Write the result to a temporary file and compare only the parts of the build info generated by git.
# If those changed, then copy the new file over. Otherwise, what you get is a build, then install
# will trigger re-linking all executables because time keeps on slippin', slippin' (into the future...)
configure_file(
"${CMAKE_CURRENT_LIST_DIR}/hsBuildInfo.inl.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/hsBuildInfo_new.inl"
ESCAPE_QUOTES @ONLY
)

if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/hsBuildInfo.inl")
set(BUILD_DIRTY TRUE)
else()
file(READ "${CMAKE_CURRENT_BINARY_DIR}/hsBuildInfo.inl" _OLD_BUILDINFO)
file(READ "${CMAKE_CURRENT_BINARY_DIR}/hsBuildInfo_new.inl" _NEW_BUILDINFO)
# remove the contents of the literal if it's volatile, eg a date/time
string(REGEX REPLACE [[(VOLATILE_[^=]*)[^;]*]] [[\1= "untracked"]] _OLD_BUILDINFO "${_OLD_BUILDINFO}")
string(REGEX REPLACE [[(VOLATILE_[^=]*)[^;]*]] [[\1= "untracked"]] _NEW_BUILDINFO "${_NEW_BUILDINFO}")
string(COMPARE NOTEQUAL "${_NEW_BUILDINFO}" "${_OLD_BUILDINFO}" BUILD_DIRTY)
endif()

if(BUILD_DIRTY)
message("Updated hsBuildInfo.inl.")
file(RENAME "${CMAKE_CURRENT_BINARY_DIR}/hsBuildInfo_new.inl" "${CMAKE_CURRENT_BINARY_DIR}/hsBuildInfo.inl")
else()
message("No change to hsBuildInfo.inl.")
file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/hsBuildInfo_new.inl")
endif()
20 changes: 20 additions & 0 deletions cmake/hsBuildInfo.inl.cmake
@@ -0,0 +1,20 @@
// Automatically generated for diff:
// @CURRENT_DIFF_HASH@

namespace plProduct
{
constexpr uint32_t PRODUCT_BRANCH_ID = @PRODUCT_BRANCH_ID@;
constexpr uint32_t PRODUCT_BUILD_ID = @PRODUCT_BUILD_ID@;
constexpr uint32_t PRODUCT_BUILD_TYPE = @PRODUCT_BUILD_TYPE@;

static const ST::string PRODUCT_CORE_NAME = ST_LITERAL("@PRODUCT_CORE_NAME@");
static const ST::string PRODUCT_SHORT_NAME = ST_LITERAL("@PRODUCT_SHORT_NAME@");
static const ST::string PRODUCT_LONG_NAME = ST_LITERAL("@PRODUCT_LONG_NAME@");
constexpr std::string_view PRODUCT_UUID = "@PRODUCT_UUID@";

static const ST::string GIT_REV = ST_LITERAL("@GIT_REV@");
static const ST::string GIT_TAG = ST_LITERAL("@GIT_TAG@");

static const ST::string VOLATILE_BUILD_DATE = ST_LITERAL("@BUILD_DATE@");
static const ST::string VOLATILE_BUILD_TIME = ST_LITERAL("@BUILD_TIME@");
};

0 comments on commit a472397

Please sign in to comment.