|
@@ -19,6 +19,8 @@ import string
|
|
|
import subprocess
|
|
|
import sys
|
|
|
|
|
|
+from package_downloader import PackageDownloader
|
|
|
+
|
|
|
SCHEMA_DESCRIPTION = """
|
|
|
Build Config Description:
|
|
|
|
|
@@ -58,7 +60,7 @@ The following keys can exist at the root level or the target-platform level:
|
|
|
* git_skip : (optional) Option to skip all git commands, requires source_path
|
|
|
|
|
|
|
|
|
-The following keys can only exist at the target platform level as they describe the specifics for that platform
|
|
|
+The following keys can only exist at the target platform level as they describe the specifics for that platform.
|
|
|
|
|
|
* cmake_generate_args : The cmake generation arguments (minus the build folder target or any configuration) for generating
|
|
|
the project for the platform (for all configurations). To perform specific generation commands (i.e.
|
|
@@ -74,10 +76,17 @@ The following keys can only exist at the target platform level as they describe
|
|
|
|
|
|
* custom_build_cmd : A list of custom scripts to run to build from the source that was pulled from git. This option is
|
|
|
mutually exclusive from the cmake_generate_args and cmake_build_args options.
|
|
|
-
|
|
|
+ see the note about environment variables below.
|
|
|
+
|
|
|
* custom_install_cmd : A list of custom scripts to run (after the custom_build_cmd) to copy and assemble the built binaries
|
|
|
into the target package folder.
|
|
|
-
|
|
|
+ this argument is optional. You could do the install in your custom build command instead.
|
|
|
+ see the note about environment variables below.
|
|
|
+
|
|
|
+* custom_test_cmd : after making the package, it will run this and expect exit code 0
|
|
|
+ this argument is optional.
|
|
|
+ see the note about environment variables below.
|
|
|
+
|
|
|
* custom_additional_compile_definitions : Any additional compile definitions to apply in the find*.cmake file for the library that will applied
|
|
|
to targets that consume this 3P library
|
|
|
|
|
@@ -90,6 +99,35 @@ The following keys can only exist at the target platform level as they describe
|
|
|
* custom_cmake_install : Custom flag for certain platforms (ie iOS) that needs the installation arguments applied during the
|
|
|
cmake generation, and not to apply the cmake install process
|
|
|
|
|
|
+* depends_on_packages : list of name of 3-TUPLES of [package name, package hash, subfolder] that 'find' files live in]
|
|
|
+ [ ["zlib-1.5.3-rev5", "some hash", ""],
|
|
|
+ ["some other package", "some other hash", "subfoldername"],
|
|
|
+ ...
|
|
|
+ ]
|
|
|
+ that we need to download and use).
|
|
|
+ - note that we don't check recursively - you must name your recursive deps!
|
|
|
+ - The packages must be on a public CDN or locally tested with FILE:// - it uses env var
|
|
|
+ "LY_PACKAGE_SERVER_URLS" which can be a semicolon seperated list of places to try.
|
|
|
+ - The packages unzip path + subfolder is added to CMAKE_MODULE_PATH if you use cmake commands.
|
|
|
+ - Otherwise you can use DOWNLOADED_PACKAGE_FOLDERS env var in your custom script and set
|
|
|
+ - CMAKE_MODULE_PATH to be that value, yourself.
|
|
|
+ - The subfolder can be empty, in which case the root of the package will be used.
|
|
|
+
|
|
|
+Note about environment variables:
|
|
|
+When custom commands are issued (build, install, and test), the following environment variables will be set
|
|
|
+for the process:
|
|
|
+ PACKAGE_ROOT = root of the package being made (where PackageInfo.json is generated/copied)
|
|
|
+ TARGET_INSTALL_ROOT = $PACKAGE_ROOT/$PACKAGE_NAME - usually where you target cmake install to
|
|
|
+ TEMP_FOLDER = the temp folder. This folder usually has subfolder 'build' and 'src'
|
|
|
+ DOWNLOADED_PACKAGE_FOLDERS = semicolon seperated list of abs paths to each downloaded package Find folder.
|
|
|
+ - usually used to set CMAKE_MODULE_PATH so it can find the packages.
|
|
|
+ - unset if there are no dependencies declared
|
|
|
+ Note that any of the above environment variables that contain paths will use system native slashes for script
|
|
|
+ compatibility, and may need to be converted to forward slash in your script on windows
|
|
|
+ if you feed it to cmake.
|
|
|
+ Also note that the working directory for all custom commands will the folder containing the build_config.json file.
|
|
|
+
|
|
|
+
|
|
|
The general layout of the build_config.json file is as follows:
|
|
|
|
|
|
{
|
|
@@ -178,6 +216,7 @@ class PackageInfo(object):
|
|
|
self.cmake_find_target = _get_value("cmake_find_target")
|
|
|
self.cmake_find_template_custom_indent = _get_value("cmake_find_template_custom_indent", default=1)
|
|
|
self.additional_src_files = _get_value("additional_src_files", required=False)
|
|
|
+ self.depends_on_packages = _get_value("depends_on_packages", required=False)
|
|
|
|
|
|
if self.cmake_find_template and self.cmake_find_source:
|
|
|
raise BuildError("Bad build config file. 'cmake_find_template' and 'cmake_find_source' cannot both be set in the configuration.")
|
|
@@ -479,6 +518,13 @@ class BuildInfo(object):
|
|
|
cwd=str(self.src_folder.absolute()))
|
|
|
if patch_result.returncode != 0:
|
|
|
raise BuildError(f"Error Applying patch {str(patch_file_path.absolute())}: {patch_result.stderr.decode('UTF-8', 'ignore')}")
|
|
|
+ # Check if there are any package dependencies.
|
|
|
+ if self.package_info.depends_on_packages:
|
|
|
+ for package_name, package_hash, _ in self.package_info.depends_on_packages:
|
|
|
+ temp_packages_folder = self.base_temp_folder
|
|
|
+ if not PackageDownloader.DownloadAndUnpackPackage(package_name, package_hash, str(temp_packages_folder)):
|
|
|
+ raise BuildError(f"Failed to download a required dependency: {package_name}")
|
|
|
+
|
|
|
|
|
|
def build_and_install_cmake(self):
|
|
|
"""
|
|
@@ -524,7 +570,20 @@ class BuildInfo(object):
|
|
|
if self.custom_toolchain_file:
|
|
|
cmake_generator_args.append( f'-DCMAKE_TOOLCHAIN_FILE="{self.custom_toolchain_file}"')
|
|
|
|
|
|
+ cmake_module_path = ""
|
|
|
+ paths_to_join = []
|
|
|
+ if self.package_info.depends_on_packages:
|
|
|
+ paths_to_join = []
|
|
|
+ for package_name, package_hash, subfolder_name in self.package_info.depends_on_packages:
|
|
|
+ package_download_location = self.base_temp_folder / package_name / subfolder_name
|
|
|
+ paths_to_join.append(str(package_download_location.resolve()))
|
|
|
+ cmake_module_path = ';'.join(paths_to_join).replace('\\', '/')
|
|
|
+
|
|
|
+ if cmake_module_path:
|
|
|
+ cmake_generate_cmd.extend([f"-DCMAKE_MODULE_PATH={cmake_module_path}"])
|
|
|
+
|
|
|
cmake_generate_cmd.extend(cmake_generator_args)
|
|
|
+
|
|
|
if custom_cmake_install:
|
|
|
cmake_generate_cmd.extend([f"-DCMAKE_INSTALL_PREFIX={str(self.build_install_folder.resolve())}"])
|
|
|
|
|
@@ -593,30 +652,45 @@ class BuildInfo(object):
|
|
|
target_folder_path.mkdir(parents=True)
|
|
|
shutil.copy2(glob_result, str(target_folder_path.resolve()), follow_symlinks=False)
|
|
|
|
|
|
+ def create_custom_env(self):
|
|
|
+ custom_env = os.environ.copy()
|
|
|
+ custom_env['TARGET_INSTALL_ROOT'] = str(self.build_install_folder.resolve())
|
|
|
+ custom_env['PACKAGE_ROOT'] = str(self.package_install_root.resolve())
|
|
|
+ custom_env['TEMP_FOLDER'] = str(self.base_temp_folder.resolve())
|
|
|
+ if self.package_info.depends_on_packages:
|
|
|
+ package_folder_list = []
|
|
|
+ for package_name, _, subfoldername in self.package_info.depends_on_packages:
|
|
|
+ package_folder_list.append(str( (self.base_temp_folder / package_name / subfoldername).resolve().absolute()))
|
|
|
+ custom_env['DOWNLOADED_PACKAGE_FOLDERS'] = ';'.join(package_folder_list)
|
|
|
+ return custom_env
|
|
|
+
|
|
|
def build_and_install_custom(self):
|
|
|
"""
|
|
|
Build and install from source using custom commands defined by 'custom_build_cmd' and 'custom_install_cmd'
|
|
|
"""
|
|
|
-
|
|
|
+ # we add TARGET_INSTALL_ROOT, TEMP_FOLDER and DOWNLOADED_PACKAGE_FOLDERS to the environ for both
|
|
|
+ # build and install, as they are useful to refer to from scripts.
|
|
|
+
|
|
|
+ env_to_use = self.create_custom_env()
|
|
|
custom_build_cmds = self.platform_config.get('custom_build_cmd', [])
|
|
|
for custom_build_cmd in custom_build_cmds:
|
|
|
|
|
|
call_result = subprocess.run(custom_build_cmd,
|
|
|
shell=True,
|
|
|
capture_output=False,
|
|
|
- cwd=str(self.base_folder))
|
|
|
+ cwd=str(self.base_folder),
|
|
|
+ env=env_to_use)
|
|
|
if call_result.returncode != 0:
|
|
|
raise BuildError(f"Error executing custom build command {custom_build_cmd}")
|
|
|
|
|
|
custom_install_cmds = self.platform_config.get('custom_install_cmd', [])
|
|
|
- custom_install_env = os.environ.copy()
|
|
|
- custom_install_env['TARGET_INSTALL_ROOT'] = str(self.build_install_folder.resolve())
|
|
|
+
|
|
|
for custom_install_cmd in custom_install_cmds:
|
|
|
call_result = subprocess.run(custom_install_cmd,
|
|
|
shell=True,
|
|
|
capture_output=False,
|
|
|
cwd=str(self.base_folder),
|
|
|
- env=custom_install_env)
|
|
|
+ env=env_to_use)
|
|
|
if call_result.returncode != 0:
|
|
|
raise BuildError(f"Error executing custom install command {custom_install_cmd}")
|
|
|
|
|
@@ -690,10 +764,8 @@ class BuildInfo(object):
|
|
|
find_cmake_content = string.Template(template_file_content).substitute(template_env)
|
|
|
|
|
|
elif self.cmake_find_source is not None:
|
|
|
-
|
|
|
find_cmake_content = self.cmake_find_source.read_text("UTF-8", "ignore")
|
|
|
|
|
|
-
|
|
|
target_cmake_find_script = self.package_install_root / self.package_info.cmake_find_target
|
|
|
target_cmake_find_script.write_text(find_cmake_content)
|
|
|
|
|
@@ -745,6 +817,22 @@ class BuildInfo(object):
|
|
|
|
|
|
pass
|
|
|
|
|
|
+ def test_package(self):
|
|
|
+ has_test_commands = self.check_build_keys(['custom_test_cmd'])
|
|
|
+ if not has_test_commands:
|
|
|
+ return
|
|
|
+
|
|
|
+ custom_test_cmds= self.platform_config.get('custom_test_cmd', [])
|
|
|
+ for custom_test_cmd in custom_test_cmds:
|
|
|
+
|
|
|
+ call_result = subprocess.run(custom_test_cmd,
|
|
|
+ shell=True,
|
|
|
+ capture_output=False,
|
|
|
+ cwd=str(self.base_folder),
|
|
|
+ env=self.create_custom_env())
|
|
|
+ if call_result.returncode != 0:
|
|
|
+ raise BuildError(f"Error executing custom test command {custom_test_cmd}")
|
|
|
+
|
|
|
def execute(self):
|
|
|
"""
|
|
|
Perform all the steps to build a folder for the 3rd party library for packaging
|
|
@@ -765,6 +853,8 @@ class BuildInfo(object):
|
|
|
# Generate the Find*.cmake file
|
|
|
self.generate_cmake()
|
|
|
|
|
|
+ self.test_package()
|
|
|
+
|
|
|
# Generate the package info file
|
|
|
self.generate_package_info()
|
|
|
|