AMDSMI CLI Initial Packaging

- Added CMake packaging to the amdsmi_cli folder
- Updated Headings in the README.md to follow markdown standard
- Updated Compatibility to be based on the built package name in bin
- Added misc error handling and import corrections
- Updated py-interface amdsmi_exception imports to work by relative path
- Cleaned up py-interface cmake & generator code for finding libamd_smi.so
- Changed line endings in tools/generator.py file to unix

Change-Id: I91858ff3dd0cb57ed9b8cd61a0ada27b6af9c51c
Signed-off-by: Maisam Arif <Maisam.Arif@amd.com>
This commit is contained in:
Maisam Arif
2023-03-17 05:34:24 -05:00
committed by Galantsev, Dmitrii
parent aa70b77ec5
commit 235c8db949
13 changed files with 300 additions and 182 deletions
+6 -1
View File
@@ -55,6 +55,7 @@ include(GNUInstallDirs)
option(BUILD_TESTS "Build test suite" OFF)
# TODO: Enable once virtualenv is installed on CI machines
option(BUILD_PACKAGE "Build python package" OFF)
option(ENABLE_CLI "Enable AMDSMI-CLI install" OFF)
option(ENABLE_LDCONFIG "Set library links and caches using ldconfig." ON)
# Set share path here because project name != amd_smi
@@ -134,11 +135,15 @@ if(BUILD_PACKAGE)
add_subdirectory("py-interface")
endif()
if(ENABLE_CLI)
add_subdirectory("amdsmi_cli")
endif()
include(CMakePackageConfigHelpers)
configure_package_config_file(
amd_smi-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/amd_smi-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/amd_smi
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${AMD_SMI}
PATH_VARS CMAKE_INSTALL_LIBDIR CMAKE_INSTALL_INCLUDEDIR CMAKE_INSTALL_BINDIR)
write_basic_package_version_file(
+21 -16
View File
@@ -1,10 +1,9 @@
# AMD System Management Interface (AMD SMI) Library
The AMD System Management Interface Library, or AMD SMI library, is a C library for Linux that provides a user space interface for applications to monitor and control AMD devices.
## Supported platforms
At initial release, the AMD SMI library will support Linux bear metal and Linux virtual machine guest for AMD GPUs. In the future release, the library will be extended to support AMD EPYC™ CPUs.
AMD SMI library can run on AMD ROCm supported platforms, please refer to [List of Supported Operating Systems and GPUs](https://docs.amd.com/bundle/ROCm-Getting-Started-Guide-v5.3/page/Introduction_to_ROCm_Getting_Started_Guide_for_Linux.html)
@@ -12,9 +11,9 @@ AMD SMI library can run on AMD ROCm supported platforms, please refer to [List o
To run the AMD SMI library, the amdgpu driver needs to be installed. Optionally, the libdrm can be
installed to query firmware information and hardware IPs.
# Building AMD SMI
## Building AMD SMI
## Additional Required software for building
### Additional Required software for building
In order to build the AMD SMI library, the following components are required. Note that the software versions listed are what was used in development. Earlier versions are not guaranteed to work:
* CMake (v3.11.0) - `pip3 install cmake`
@@ -26,31 +25,35 @@ In order to build the AMD SMI python package, the following components are requi
* virtualenv - `pip3 install virtualenv`
In order to build the latest documentation, the following are required:
* DOxygen (1.8.11)
* latex (pdfTeX 3.14159265-2.6-1.40.16)
The source code for AMD SMI is available on Github.
After the AMD SMI library git repository has been cloned to a local Linux machine, building the library is achieved by following the typical CMake build sequence. Specifically,
After the AMD SMI library git repository has been cloned to a local Linux machine, the Default location for the library and headers is /opt/rocm. Building the library is achieved by following the typical CMake build sequence, specifically:
```bash
mkdir -p build
cd build
cmake ..
make -j $(nproc)
# Install library file and header; default location is /opt/rocm
make install```
make install
```
The built library will appear in the `build` folder.
To build the rpm and deb packages follow the above steps with:
```bash
make package```
## Documentation
```bash
make package
```
### Documentation
The reference manual, `refman.pdf` will be in the `latex` directory upon a successful build.
## Building the Tests
### Building the Tests
In order to verify the build and capability of AMD SMI on your system and to see an example of how AMD SMI can be used, you may build and run the tests that are available in the repo. To build the tests, follow these steps:
@@ -61,21 +64,23 @@ cmake -DBUILD_TESTS=ON <location of root of AMD SMI library CMakeLists.txt>
make -j $(nproc)
```
## Run the Tests
### Run the Tests
To run the test, execute the program `amdsmitst` that is built from the steps above.
# Usage Basics
## Usage Basics
### Device/Socket handles
## Device/Socket handles
Many of the functions in the library take a "socket handle" or "device handle". The socket is an abstraction of hardware physical socket. This will enable amd-smi to provide a better representation of the hardware to user. Although there is always one distinct GPU for a socket, the APU may have both
GPU device and CPU device on the same socket. Moreover, for MI200, it may have multiple GCDs.
To discover the sockets in the system, `amdsmi_get_socket_handles()` is called to get list of sockets
handles, which in turn can be used to query the devices in that socket using `amdsmi_get_device_handles()`. The device handler is used to distinguish the detected devices from one another. It is important to note that a device may end up with a different device handles after restart application, so a device handle should not be relied upon to be constant over process.
# Hello AMD SMI
The only required AMD-SMI call for any program that wants to use AMD-SMI is the `amdsmi_init()` call. This call initializes some internal data structures that will be used by subsequent AMD-SMI calls. In the call, a flag can be passed if the application is only interested in a specific device type.
## Hello AMD SMI
The only required AMD-SMI call for any program that wants to use AMD-SMI is the `amdsmi_init()` call. This call initializes some internal data structures that will be used by subsequent AMD-SMI calls. In the call, a flag can be passed if the application is only interested in a specific device type.
When AMD-SMI is no longer being used, `amdsmi_shut_down()` should be called. This provides a way to do any releasing of resources that AMD-SMI may have held.
+89
View File
@@ -0,0 +1,89 @@
message("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
message(" CMake AMDSMI CLI Install ")
message("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&")
# Set CLI Build Directory
set(CLI_BUILD_DIR "amdsmi_cli" CACHE STRING "")
set(SHARE_WHL_LOCATION "${SHARE_INSTALL_PREFIX}/${AMD_SMI}/amdsmi-0.1-py3-none-any.whl")
# The CLI requires the python amdsmi wrapper whl file to exist
add_custom_target(
amdsmi_cli
DEPENDS SHARE_WHL_LOCATION)
# if Python3 is found but the version is below 3.7 - Python3_FOUND is set to FALSE
find_package(Python3 3.7 COMPONENTS Interpreter)
# WARN: This is a HACK to pass compile on AMD rhel8 CI systems!
# Those still use python3.6 which is too old for this project!
if(NOT Python3_FOUND)
message(AUTHOR_WARNING "Python3 DOESN'T EXIST OR VERSION IS TOO OLD!: ${Python3_VERSION}")
# WARN: EXIT CURRENT CMAKE FILE
return()
endif()
add_custom_target(
amdsmi_whl_install
COMMAND ${Python3_EXECUTABLE} -m pip install --upgrade --force-reinstall SHARE_WHL_LOCATION)
# symlinking instead of copying avoids unnecessarry regeneration of packaged files
add_custom_command(
OUTPUT ${CLI_BUILD_DIR}/pyproject.toml
${CLI_BUILD_DIR}/__init__.py
${CLI_BUILD_DIR}/_version.py
${CLI_BUILD_DIR}/amdsmi_cli.py
${CLI_BUILD_DIR}/amdsmi_commands.py
${CLI_BUILD_DIR}/amdsmi_helpers.py
${CLI_BUILD_DIR}/amdsmi_logger.py
${CLI_BUILD_DIR}/amdsmi_parser.py
${CLI_BUILD_DIR}/BDF.py
DEPENDS amdsmi_cli
amdsmi_whl_install
COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/pyproject.toml ${CLI_BUILD_DIR}/
COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py ${CLI_BUILD_DIR}/
COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/_version.py ${CLI_BUILD_DIR}/
COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/amdsmi_cli.py ${CLI_BUILD_DIR}/
COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/amdsmi_commands.py ${CLI_BUILD_DIR}/
COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/amdsmi_helpers.py ${CLI_BUILD_DIR}/
COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/amdsmi_logger.py ${CLI_BUILD_DIR}/
COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/amdsmi_parser.py ${CLI_BUILD_DIR}/
COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/BDF.py ${CLI_BUILD_DIR}/)
install(
FILES _version.py
amdsmi_commands.py
amdsmi_helpers.py
amdsmi_init.py
amdsmi_logger.py
amdsmi_parser.py
BDF.py
DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/${AMD_SMI}/amdsmi_cli)
install(
FILES ${CMAKE_CURRENT_SOURCE_DIR}/amdsmi_cli.py
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ
GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}/${AMD_SMI}/amdsmi_cli)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/bin/amd-smi
DESTINATION ${CMAKE_INSTALL_BINDIR})
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/bin/gpuv-smi
DESTINATION ${CMAKE_INSTALL_BINDIR})
# symlink amdsmi_cli.py to amd-smi
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
add_custom_target(
link_amdsmi_cli ALL
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E create_symlink
../${CMAKE_INSTALL_LIBEXECDIR}/${AMD_SMI}/amdsmi_cli/amdsmi_cli.py
${CMAKE_CURRENT_BINARY_DIR}/bin/amd-smi)
add_custom_target(
link_gpuvsmi_cli ALL
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${CMAKE_COMMAND} -E create_symlink
../${CMAKE_INSTALL_LIBEXECDIR}/${AMD_SMI}/amdsmi_cli/amdsmi_cli.py
${CMAKE_CURRENT_BINARY_DIR}/bin/gpuv-smi)
View File
+10 -4
View File
@@ -25,10 +25,18 @@ import sys
from amdsmi_commands import AMDSMICommands
from amdsmi_parser import AMDSMIParser
from amdsmi_logger import AMDSMILogger
if __name__ == "__main__":
amd_smi_commands = AMDSMICommands()
# Set compatability mode based on which cli mapping user selects
if 'gpuv-smi' in sys.argv[0]:
compatibility = AMDSMILogger.LoggerCompatibility.gpuvsmi.value
elif 'rocm-smi' in sys.argv[0]:
compatibility = AMDSMILogger.LoggerCompatibility.rocmsmi.value
else:
compatibility = AMDSMILogger.LoggerCompatibility.amdsmi.value
amd_smi_commands = AMDSMICommands(compatibility=compatibility)
amd_smi_parser = AMDSMIParser(amd_smi_commands.version,
amd_smi_commands.discovery,
amd_smi_commands.static,
@@ -59,8 +67,6 @@ if __name__ == "__main__":
'ERROR': logging.ERROR,
'CRITICAL': logging.CRITICAL}
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging_dict[args.loglevel])
if args.compatibility:
amd_smi_commands.logger.compatibility = args.compatibility
# Execute subcommands
args.func(args)
+9 -3
View File
@@ -31,8 +31,9 @@ destination.
from _version import __version__
from amdsmi_helpers import *
from amdsmi_helpers import AMDSMIHelpers
from amdsmi_logger import AMDSMILogger
from amdsmi import amdsmi_interface
class AMDSMICommands():
@@ -744,9 +745,14 @@ class AMDSMICommands():
'rpm' : fan_rpm,
'usage' : fan_percent}
if args.pcie_usage:
pcie_link_status = amdsmi_interface.amdsmi_get_pcie_link_status(args.gpu)
try:
pcie_link_status = amdsmi_interface.amdsmi_get_pcie_link_status(args.gpu)
pcie_link_status_call = True
except amdsmi_interface.AmdSmiLibraryException as err:
pcie_link_status = err.get_error_info()
pcie_link_status_call = False
if self.logger.is_human_readable_format():
if self.logger.is_human_readable_format() and pcie_link_status_call:
unit ='MT/s'
pcie_link_status['pcie_speed'] = f"{pcie_link_status['pcie_speed']} {unit}"
+1 -2
View File
@@ -29,8 +29,7 @@ import sys
from pathlib import Path
sys.path.insert( 0, "../build/python_package/amdsmi")
import amdsmi_interface
import amdsmi as amdsmi_interface
# Using basic python logging for user errors and development
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.ERROR) # User level logging
+5 -5
View File
@@ -34,7 +34,7 @@ class AMDSMILogger():
self.output = {}
self.multiple_device_output = []
self.watch_output = []
self.compatibility = compatibility # amdsmi, gpuvsmi, or rocmsmi
self.compatibility = compatibility # amd-smi, gpuv-smi, or rocm-smi
self.format = format # csv, json, or human_readable
self.destination = destination # stdout, path to a file (append)
self.amd_smi_helpers = AMDSMIHelpers()
@@ -46,7 +46,7 @@ class AMDSMILogger():
csv = 'csv'
human_readable = 'human_readable'
class Loggercompatibility(Enum):
class LoggerCompatibility(Enum):
"""Enum for logger compatibility"""
amdsmi = 'amdsmi'
rocmsmi = 'rocmsmi'
@@ -66,15 +66,15 @@ class AMDSMILogger():
def is_amdsmi_compatibility(self):
return self.compatibility == self.Loggercompatibility.amdsmi.value
return self.compatibility == self.LoggerCompatibility.amdsmi.value
def is_rocmsmi_compatibility(self):
return self.compatibility == self.Loggercompatibility.rocmsmi.value
return self.compatibility == self.LoggerCompatibility.rocmsmi.value
def is_gpuvsmi_compatibility(self):
return self.compatibility == self.Loggercompatibility.gpuvsmi.value
return self.compatibility == self.LoggerCompatibility.gpuvsmi.value
def store_output(self, device_handle, argument, data):
-5
View File
@@ -183,7 +183,6 @@ class AMDSMIParser(argparse.ArgumentParser):
csv_help = "Displays output in CSV format (human readable by default)."
file_help = "Saves output into a file on the provided path (stdout by default)."
loglevel_help = "Set the logging level for the parser commands"
compatibility_help = "Display output in gpuvsmi or rocmsmi legacy format if possible"
command_modifier_group = subcommand_parser.add_argument_group('Command Modifiers')
@@ -197,10 +196,6 @@ class AMDSMIParser(argparse.ArgumentParser):
command_modifier_group.add_argument('--loglevel', action='store', required=False, help=loglevel_help, default='ERROR',
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"])
# Output Compatibility options
command_modifier_group.add_argument('--compatibility', action='store', required=False, help=compatibility_help,
choices=["amdsmi", "gpuvsmi", "rocmsmi"], default='amdsmi')
def _add_device_arguments(self, subcommand_parser, required=False):
# Device arguments help text
+2 -2
View File
@@ -64,11 +64,11 @@ else()
# extract clang version manually because find_package(clang) doesn't work
execute_process(COMMAND ${clang} --version OUTPUT_VARIABLE clang_full_version_string)
string (REGEX REPLACE ".*clang version ([0-9]+\\.[0-9]+).*" "\\1" CLANG_VERSION_STRING ${clang_full_version_string})
if(CLANG_VERSION_STRING VERSION_EQUAL 14.0)
if(CLANG_VERSION_STRING VERSION_EQUAL clang_ver)
message("GOOD CLANG VERSION: ${CLANG_VERSION_STRING}")
set(GOOD_CLANG_FOUND TRUE)
else()
message(AUTHOR_WARNING "CLANG VERSION TOO OLD!: ${CLANG_VERSION_STRING}")
message(AUTHOR_WARNING "${clang} VERSION TOO OLD!: ${CLANG_VERSION_STRING}")
endif()
endif()
if(NOT GOOD_CLANG_FOUND)
+1 -2
View File
@@ -26,8 +26,7 @@ from enum import IntEnum
from collections.abc import Iterable
from . import amdsmi_wrapper
from amdsmi_exception import *
from .amdsmi_exception import *
class AmdSmiInitFlags(IntEnum):
ALL_DEVICES = amdsmi_wrapper.AMDSMI_INIT_ALL_DEVICES
+19 -11
View File
@@ -20,7 +20,6 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
import os
# -*- coding: utf-8 -*-
#
# TARGET arch is: ['-I/usr/lib/llvm-14/lib/clang/14.0.0/include']
@@ -28,8 +27,10 @@ import os
# POINTER_SIZE is: 8
# LONGDOUBLE_SIZE is: 16
#
import ctypes
import os
import ctypes
from pathlib import Path
c_int128 = ctypes.c_ubyte*16
c_uint128 = c_int128
@@ -168,16 +169,23 @@ def char_pointer_cast(string, encoding='utf-8'):
_libraries = {}
if os.path.isfile('@CPACK_PACKAGING_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@/libamd_smi.so'):
# try to find library in install directory provided by CMake
_libraries['libamd_smi.so'] = ctypes.CDLL(os.path.join('@CPACK_PACKAGING_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@', 'libamd_smi.so'))
elif os.path.isfile('/opt/rocm/lib/libamd_smi.so'):
# try /opt/rocm/lib as a fallback
_libraries['libamd_smi.so'] = ctypes.CDLL(os.path.join('/opt/rocm/lib', 'libamd_smi.so'))
else:
# lastly - search in current directory
_libraries['libamd_smi.so'] = ctypes.CDLL(os.path.join(os.path.dirname(__file__), 'libamd_smi.so'))
libamd_smi_cpack = Path("@CPACK_PACKAGING_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@/libamd_smi.so")
libamd_smi_optrocm = Path("/opt/rocm/lib/libamd_smi.so")
libamd_smi_parent_dir = Path(__file__).resolve().parent / "libamd_smi.so"
libamd_smi_cwd = Path.cwd()
if libamd_smi_cpack.is_file():
# try to find library in install directory provided by CMake
_libraries['libamd_smi.so'] = ctypes.CDLL(libamd_smi_cpack)
elif libamd_smi_optrocm.is_file():
# try /opt/rocm/lib as a fallback
_libraries['libamd_smi.so'] = ctypes.CDLL(libamd_smi_optrocm)
elif libamd_smi_parent_dir.is_file():
# try to fall back to parent directory
_libraries['libamd_smi.so'] = ctypes.CDLL(libamd_smi_parent_dir)
else:
# lastly - search in current working directory
_libraries['libamd_smi.so'] = ctypes.CDLL(libamd_smi_cwd)
+137 -131
View File
@@ -1,131 +1,137 @@
#
# Copyright (C) 2023 Advanced Micro Devices. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
import os
import sys
import argparse
import tempfile
import shutil
import platform
from subprocess import run, PIPE
from ctypeslib.clang2py import main as clangToPy
HEADER = \
"""
#
# Copyright (C) 2023 Advanced Micro Devices. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
import os
"""
def parseArgument():
parser = argparse.ArgumentParser(description="parse input arguments")
parser.add_argument('-o','--output', type=str, required=True,
help='The output file name')
parser.add_argument('-i','--input', type=str, required=True,
help='The input file name')
parser.add_argument('-l', '--library', type=str, required=True,
help='Loading dynamic link libraries')
args = vars(parser.parse_args())
return args['output'], args['input'], args['library']
def replace_line(full_path_file_name, string_to_repalce, new_string):
fh, abs_path = tempfile.mkstemp()
with os.fdopen(fh, 'w') as new_file:
new_file.write(HEADER)
with open(full_path_file_name, 'r+') as old_file:
for line in old_file:
new_file.write(line.replace(string_to_repalce, new_string))
shutil.copymode(full_path_file_name, abs_path)
os.remove(full_path_file_name)
shutil.move(abs_path, full_path_file_name)
def main():
output_file, input_file, library = parseArgument()
library_name = os.path.basename(library)
clang_include_dir = \
run(["clang", "--print-resource-dir"], stdout=PIPE, stderr=PIPE, encoding="utf-8").stdout.strip()
os_platform = platform.system()
if os_platform == "Windows":
clang_include_dir += "\include"
if "Program Files(x86)" in clang_include_dir:
clang_include_dir = clang_include_dir.replace("Program Files(x86)", "Progra~2")
elif "Program Files" in clang_include_dir:
clang_include_dir = clang_include_dir.replace("Program Files", "Progra~1")
arguments = [input_file, "-o", output_file]
line_to_replace = "_libraries['FIXME_STUB'] = FunctionFactoryStub() # ctypes.CDLL('FIXME_STUB')"
new_line = "_libraries['FIXME_STUB'] = ctypes.CDLL('{}')".format(library_name)
elif os_platform == "Linux":
clang_include_dir += "/include"
arguments = [input_file, "-o", output_file, "-l", library]
library_path = os.path.join(os.path.dirname(__file__), library)
line_to_replace = "_libraries['{}'] = ctypes.CDLL('{}')".format(library_name, library_path)
new_line = """
if os.path.isfile('@CPACK_PACKAGING_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@/{0}'):
# try to find library in install directory provided by CMake
_libraries['{0}'] = ctypes.CDLL(os.path.join('@CPACK_PACKAGING_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@', '{0}'))
elif os.path.isfile('/opt/rocm/lib/{0}'):
# try /opt/rocm/lib as a fallback
_libraries['{0}'] = ctypes.CDLL(os.path.join('/opt/rocm/lib', '{0}'))
else:
# lastly - search in current directory
_libraries['{0}'] = ctypes.CDLL(os.path.join(os.path.dirname(__file__), '{0}'))
""".format(library_name)
else:
print("Unknown operating system. It is only supporing Linux and Windows.")
return
arguments.append(f"--clang-args=-I" + clang_include_dir)
clangToPy(arguments)
replace_line(output_file, line_to_replace, new_line)
if __name__ == "__main__":
main()
#
# Copyright (C) 2023 Advanced Micro Devices. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
import os
import argparse
import tempfile
import shutil
import platform
from subprocess import run, PIPE
from ctypeslib.clang2py import main as clangToPy
HEADER = \
"""
#
# Copyright (C) 2023 Advanced Micro Devices. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
import os
"""
def parseArgument():
parser = argparse.ArgumentParser(description="parse input arguments")
parser.add_argument('-o','--output', type=str, required=True,
help='The output file name')
parser.add_argument('-i','--input', type=str, required=True,
help='The input file name')
parser.add_argument('-l', '--library', type=str, required=True,
help='Loading dynamic link libraries')
args = vars(parser.parse_args())
return args['output'], args['input'], args['library']
def replace_line(full_path_file_name, string_to_repalce, new_string):
fh, abs_path = tempfile.mkstemp()
with os.fdopen(fh, 'w') as new_file:
new_file.write(HEADER)
with open(full_path_file_name, 'r+', encoding='UTF-8') as old_file:
for line in old_file:
new_file.write(line.replace(string_to_repalce, new_string))
shutil.copymode(full_path_file_name, abs_path)
os.remove(full_path_file_name)
shutil.move(abs_path, full_path_file_name)
def main():
output_file, input_file, library = parseArgument()
library_name = os.path.basename(library)
clang_include_dir = \
run(["clang", "--print-resource-dir"], stdout=PIPE, stderr=PIPE, encoding="utf-8").stdout.strip()
os_platform = platform.system()
if os_platform == "Windows":
clang_include_dir += "\include"
if "Program Files(x86)" in clang_include_dir:
clang_include_dir = clang_include_dir.replace("Program Files(x86)", "Progra~2")
elif "Program Files" in clang_include_dir:
clang_include_dir = clang_include_dir.replace("Program Files", "Progra~1")
arguments = [input_file, "-o", output_file]
line_to_replace = "_libraries['FIXME_STUB'] = FunctionFactoryStub() # ctypes.CDLL('FIXME_STUB')"
new_line = "_libraries['FIXME_STUB'] = ctypes.CDLL('{}')".format(library_name)
elif os_platform == "Linux":
clang_include_dir += "/include"
arguments = [input_file, "-o", output_file, "-l", library]
library_path = os.path.join(os.path.dirname(__file__), library)
line_to_replace = "_libraries['{}'] = ctypes.CDLL('{}')".format(library_name, library_path)
new_line = f"""from pathlib import Path
libamd_smi_cpack = Path("@CPACK_PACKAGING_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@/{library_name}")
libamd_smi_optrocm = Path("/opt/rocm/lib/{library_name}")
libamd_smi_parent_dir = Path(__file__).resolve().parent / "{library_name}"
libamd_smi_cwd = Path.cwd()
if libamd_smi_cpack.is_file():
# try to find library in install directory provided by CMake
_libraries['{library_name}'] = ctypes.CDLL(libamd_smi_cpack)
elif libamd_smi_optrocm.is_file():
# try /opt/rocm/lib as a fallback
_libraries['{library_name}'] = ctypes.CDLL(libamd_smi_optrocm)
elif libamd_smi_parent_dir.is_file():
# try to fall back to parent directory
_libraries['{library_name}'] = ctypes.CDLL(libamd_smi_parent_dir)
else:
# lastly - search in current working directory
_libraries['{library_name}'] = ctypes.CDLL(libamd_smi_cwd)"""
else:
print("Unknown operating system. It is only supporing Linux and Windows.")
return
arguments.append("--clang-args=-I" + clang_include_dir)
clangToPy(arguments)
replace_line(output_file, line_to_replace, new_line)
if __name__ == "__main__":
main()