-
Notifications
You must be signed in to change notification settings - Fork 35
Retrieve HWLOC API version from hwloc.h header #492
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
Retrieve HWLOC API version from hwloc.h header #492
Conversation
I've tested this change on my fork with 2 scenarios (in qemu workflow):
Both scenarios properly reported the version. On the side note, we still use 2.3.0 as our minimum, but it won't work with many_preferred, I guess (as I wrote here) |
cmake/FindLIBHWLOC.cmake
Outdated
if(EXISTS "${LIBHWLOC_INCLUDE_DIR}/hwloc.h") | ||
file(STRINGS "${LIBHWLOC_INCLUDE_DIR}/hwloc.h" LIBHWLOC_API_VERSION | ||
REGEX "#define[ \t]HWLOC_API_VERSION[ \t]0x[0-9]+") | ||
string(REGEX | ||
REPLACE "#define[ \t]HWLOC_API_VERSION[ \t](0x[0-9]+)" "\\1" | ||
LIBHWLOC_API_VERSION "${LIBHWLOC_API_VERSION}") | ||
|
||
math(EXPR LIBHWLOC_API_PATCH "(${LIBHWLOC_API_VERSION} & 0xFF)") | ||
math(EXPR LIBHWLOC_API_MINOR "(${LIBHWLOC_API_VERSION} & 0xFF00) >> 8") | ||
math(EXPR LIBHWLOC_API_MAJOR | ||
"(${LIBHWLOC_API_VERSION} & 0xFF0000) >> 16") | ||
|
||
set(LIBHWLOC_API_VERSION | ||
"${LIBHWLOC_API_MAJOR}.${LIBHWLOC_API_MINOR}.${LIBHWLOC_API_PATCH}") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: parsing c header in cmake by using regex is a red flag for me - we could just create C program to extract this information - i.e like one bellow. I'm not fully convinced that this is better - but regex and math inside of cmake also are not to great.
Following code is AI generated and might not work. It might be better to just create support tool and compile it normally instead of using try_run - but i'm leaving this to your consideration.
if(EXISTS "${LIBHWLOC_INCLUDE_DIR}/hwloc.h") | |
file(STRINGS "${LIBHWLOC_INCLUDE_DIR}/hwloc.h" LIBHWLOC_API_VERSION | |
REGEX "#define[ \t]HWLOC_API_VERSION[ \t]0x[0-9]+") | |
string(REGEX | |
REPLACE "#define[ \t]HWLOC_API_VERSION[ \t](0x[0-9]+)" "\\1" | |
LIBHWLOC_API_VERSION "${LIBHWLOC_API_VERSION}") | |
math(EXPR LIBHWLOC_API_PATCH "(${LIBHWLOC_API_VERSION} & 0xFF)") | |
math(EXPR LIBHWLOC_API_MINOR "(${LIBHWLOC_API_VERSION} & 0xFF00) >> 8") | |
math(EXPR LIBHWLOC_API_MAJOR | |
"(${LIBHWLOC_API_VERSION} & 0xFF0000) >> 16") | |
set(LIBHWLOC_API_VERSION | |
"${LIBHWLOC_API_MAJOR}.${LIBHWLOC_API_MINOR}.${LIBHWLOC_API_PATCH}") | |
# Define the C code that accepts an argument for the version part | |
set(HWLOC_VERSION_CODE " | |
#include <hwloc.h> | |
#include <stdlib.h> | |
int main(int argc, char* argv[]) { | |
int part = atoi(argv[1]); // Convert the argument to an integer | |
if(part == 0) { | |
return (HWLOC_API_VERSION & 0xFF0000) >> 16; // Major version | |
} else if(part == 1) { | |
return (HWLOC_API_VERSION & 0xFF00) >> 8; // Minor version | |
} | |
return (HWLOC_API_VERSION & 0xFF); // Patch version | |
}") | |
foreach(idx RANGE 0 2) | |
try_run(RUN_RESULT_VAR COMPILE_RESULT_VAR | |
${CMAKE_BINARY_DIR} | |
"${HWLOC_VERSION_CODE}" | |
ARGS ${idx} | |
CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${LIBHWLOC_INCLUDE_DIR}" | |
COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT | |
RUN_OUTPUT_VARIABLE VERSION_OUTPUT) | |
if(${idx} EQUAL 0) | |
set(LIBHWLOC_API_MAJOR ${VERSION_OUTPUT}) | |
elseif(${idx} EQUAL 1) | |
set(LIBHWLOC_API_MINOR ${VERSION_OUTPUT}) | |
else() | |
set(LIBHWLOC_API_PATCH ${VERSION_OUTPUT}) | |
endif() | |
endforeach() | |
set(LIBHWLOC_API_VERSION "${LIBHWLOC_API_MAJOR}.${LIBHWLOC_API_MINOR}.${LIBHWLOC_API_PATCH}") | |
an approach with separate program (also AI generated not tested)
#include <stdio.h>
#include <stdlib.h>
#include "hwloc.h"
int main(int argc, char** argv) {
int major = (HWLOC_API_VERSION & 0xFF0000) >> 16;
int minor = (HWLOC_API_VERSION & 0xFF00) >> 8;
int patch = (HWLOC_API_VERSION & 0xFF);
int component = atoi(argv[1]); // Convert the argument to an integer
if(component == 0) {
return major;
} else if(component == 1) {
return minor;
} else {
return patch;
}
}
if(EXISTS "${LIBHWLOC_INCLUDE_DIR}/hwloc.h")
# Create an executable for extracting the version
add_executable(hwloc_version_extractor hwloc_version_extractor.c)
target_include_directories(hwloc_version_extractor PRIVATE ${LIBHWLOC_INCLUDE_DIR})
# Execute the program for each version component
foreach(version_idx IN ITEMS 0 1 2)
execute_process(COMMAND hwloc_version_extractor ${version_idx}
RESULT_VARIABLE result
OUTPUT_VARIABLE output_var
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
# Assigning the exit code directly to the version component variable
if(version_idx EQUAL 0)
set(LIBHWLOC_API_MAJOR ${result})
elseif(version_idx EQUAL 1)
set(LIBHWLOC_API_MINOR ${result})
else()
set(LIBHWLOC_API_PATCH ${result})
endif()
endforeach()
# Combine the version components
set(LIBHWLOC_API_VERSION "${LIBHWLOC_API_MAJOR}.${LIBHWLOC_API_MINOR}.${LIBHWLOC_API_PATCH}")
endif()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH we could just do entire version check by using c program. (create program which fails to compile if HWLOC version is to low)
cmake/FindLIBHWLOC.cmake
Outdated
if(EXISTS "${LIBHWLOC_INCLUDE_DIR}/hwloc.h") | ||
file(STRINGS "${LIBHWLOC_INCLUDE_DIR}/hwloc.h" LIBHWLOC_API_VERSION | ||
REGEX "#define[ \t]HWLOC_API_VERSION[ \t]0x[0-9]+") | ||
string(REGEX | ||
REPLACE "#define[ \t]HWLOC_API_VERSION[ \t](0x[0-9]+)" "\\1" | ||
LIBHWLOC_API_VERSION "${LIBHWLOC_API_VERSION}") | ||
|
||
math(EXPR LIBHWLOC_API_PATCH "(${LIBHWLOC_API_VERSION} & 0xFF)") | ||
math(EXPR LIBHWLOC_API_MINOR "(${LIBHWLOC_API_VERSION} & 0xFF00) >> 8") | ||
math(EXPR LIBHWLOC_API_MAJOR | ||
"(${LIBHWLOC_API_VERSION} & 0xFF0000) >> 16") | ||
|
||
set(LIBHWLOC_API_VERSION | ||
"${LIBHWLOC_API_MAJOR}.${LIBHWLOC_API_MINOR}.${LIBHWLOC_API_PATCH}") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a more easy way, I think. Sometimes I heard about writing code to determine the version, so I wrote the following:
CmakeLists.txt
project(test LANGUAGES C CXX)
cmake_minimum_required(VERSION 3.22)
# Include the header file
set(CMAKE_REQUIRED_FLAGS "-std=c++17")
include(CheckCXXSourceCompiles)
try_run(
HWLOC_RUN_RESULT # Variable to store the run result (exit code)
HWLOC_COMPILE_RESULT # Variable to store the compile result (TRUE/FALSE)
"${CMAKE_SOURCE_DIR}" # Directory to build the test executable
SOURCES
"${CMAKE_SOURCE_DIR}/main.cpp"
RUN_OUTPUT_VARIABLE HWLOC_RUN_OUTPUT # Variable to store the output of the test executable
)
if(HWLOC_COMPILE_RESULT)
message("hwloc version: ${HWLOC_RUN_OUTPUT}")
else()
message("Failed to determine hwloc version")
endif()
and main.cpp
#include <cstdio>
#include "hwloc.h"
int main() {
// printf("Value: %d", HWLOC_API_VERSION);
int LIBHWLOC_API_PATCH = HWLOC_API_VERSION & 0xFF;
int LIBHWLOC_API_MINOR = (HWLOC_API_VERSION >> 8) & 0xFF;
int LIBHWLOC_API_MAJOR = (HWLOC_API_VERSION >> 16) & 0xFF;
printf("%d.%d.%d", LIBHWLOC_API_MAJOR, LIBHWLOC_API_MINOR, LIBHWLOC_API_PATCH);
return 0;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Notice, I've created own hwloc.h file with: #define HWLOC_API_VERSION 0x00030000
for development purposes, so #include "hwloc.h"
can be changed to other value.
4a1d10b
to
843d0aa
Compare
@lplewa @KFilipek thanks for the suggestions. I've combined your solutions. Unfortunately, CMake 3.14 doesn't support building source code from a CMake variable. As a workaround, I had CMake write this code into a file in the build directory. @lukaszstolarczuk could I ask you to test this solution with the scenarios you tested previously? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, always you can leave our footprint as a coauthors :)
843d0aa
to
9db0d3f
Compare
The FindLIBHWLOC.cmake module previously used the config.h header to retrieve the HWLOC library version. This header was not always present depending on how the library was distributed. To address this issue, we now rely on the HWLOC API version retrieved from hwloc.h, the main HWLOC library header. Co-authored-by: Łukasz Plewa <[email protected]> Co-authored-by: Krzysztof Filipek <[email protected]>
9db0d3f
to
5b35db5
Compare
Done :). |
@igchor, you can tests this on your PR in UR |
The FindLIBHWLOC.cmake module previously used the config.h header to retrieve the HWLOC library version. This header was not always present depending on how the library was distributed. To address this issue, we now rely on the HWLOC API version retrieved from hwloc.h, the main HWLOC library header.
Description
Checklist