mirror of
https://github.com/YosysHQ/yosys
synced 2026-05-25 11:26:22 +00:00
Migrate build system to CMake
See #5895 for details. This commit does not include CI or documentation changes.
This commit is contained in:
parent
9d0cdb8551
commit
9b087b4aa7
207 changed files with 5202 additions and 2294 deletions
40
cmake/CheckLibcFeatures.cmake
Normal file
40
cmake/CheckLibcFeatures.cmake
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
include(CMakePushCheckState)
|
||||
include(CheckSourceCompiles)
|
||||
include(CheckCXXSymbolExists)
|
||||
|
||||
function(check_glob)
|
||||
check_cxx_symbol_exists(glob "glob.h" HAVE_GLOB)
|
||||
return (PROPAGATE HAVE_BLOB)
|
||||
endfunction()
|
||||
|
||||
function(check_pthread_create)
|
||||
if (Threads_FOUND)
|
||||
# On WASI, `pthread_create()` is always available, but always fails on triples without threading
|
||||
# support. Probe for it while requesting the stub implementation to be hidden, otherwise we will
|
||||
# end up always crashing at runtime on thread creation.
|
||||
cmake_push_check_state(RESET)
|
||||
set(CMAKE_REQUIRED_DEFINITIONS -D_WASI_STRICT_PTHREAD)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
|
||||
check_source_compiles(CXX [[
|
||||
#include <pthread.h>
|
||||
int main() {
|
||||
pthread_create(0, 0, 0, 0);
|
||||
}
|
||||
]] HAVE_PTHREAD_CREATE)
|
||||
cmake_pop_check_state()
|
||||
endif()
|
||||
return (PROPAGATE HAVE_PTHREAD_CREATE)
|
||||
endfunction()
|
||||
|
||||
function(check_system)
|
||||
check_cxx_symbol_exists(system "stdlib.h" HAVE_SYSTEM)
|
||||
endfunction()
|
||||
|
||||
function(check_popen)
|
||||
check_cxx_symbol_exists(popen "stdio.h" HAVE_POPEN)
|
||||
if (NOT HAVE_POPEN)
|
||||
unset(HAVE_POPEN CACHE)
|
||||
# https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/popen-wpopen
|
||||
check_cxx_symbol_exists(_popen "stdio.h" HAVE_POPEN)
|
||||
endif()
|
||||
endfunction()
|
||||
35
cmake/Condition.cmake
Normal file
35
cmake/Condition.cmake
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Syntax:
|
||||
#
|
||||
# condition(<var> <expr>...)
|
||||
#
|
||||
# If `<expr>...` is truthful (evaluated as in `if()`) then assigns 1 to `<var>`, else assigns 0.
|
||||
# The assigned value is `0`/`1` rather than `TRUE`/`FALSE` for ease of use in generator expressions.
|
||||
# Note that `<expr>...` *must* be unquoted.
|
||||
#
|
||||
# To understand how a certain outcome is reached, reconfigure the project with `--log-level VERBOSE`.
|
||||
#
|
||||
# Believe it or not, CMake doesn't have this built in!
|
||||
#
|
||||
macro(condition var)
|
||||
if (${ARGN})
|
||||
set(${var} 1)
|
||||
else()
|
||||
set(${var} 0)
|
||||
endif()
|
||||
|
||||
set(_debug_expr)
|
||||
foreach (token ${ARGN})
|
||||
if (DEFINED ${token})
|
||||
if (${${token}})
|
||||
list(APPEND _debug_expr "${token}:1")
|
||||
else()
|
||||
list(APPEND _debug_expr "${token}:0")
|
||||
endif()
|
||||
else()
|
||||
list(APPEND _debug_expr "${token}")
|
||||
endif()
|
||||
endforeach()
|
||||
string(JOIN " " _debug_expr ${_debug_expr})
|
||||
message(VERBOSE " ${var} = ${${var}} (${_debug_expr})")
|
||||
unset(_debug_expr)
|
||||
endmacro()
|
||||
24
cmake/FindDlfcn.cmake
Normal file
24
cmake/FindDlfcn.cmake
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
include(CMakePushCheckState)
|
||||
include(CheckCXXSymbolExists)
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
if (WIN32 OR MSYS)
|
||||
# Windows; dlopen is available via a polyfill `libs/dlfcn-win32`.
|
||||
set(Dlfcn_LIBRARIES dlfcn)
|
||||
else()
|
||||
# Unix and Wasm; dlopen may or may not be available depending on platform.
|
||||
cmake_push_check_state(RESET)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_DL_LIBS})
|
||||
check_cxx_symbol_exists(dlopen "dlfcn.h" HAVE_DLOPEN)
|
||||
cmake_pop_check_state()
|
||||
|
||||
if (HAVE_DLOPEN)
|
||||
add_library(dlfcn INTERFACE)
|
||||
target_link_libraries(dlfcn INTERFACE ${CMAKE_DL_LIBS})
|
||||
set(Dlfcn_LIBRARIES dlfcn)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package_handle_standard_args(Dlfcn
|
||||
REQUIRED_VARS Dlfcn_LIBRARIES
|
||||
)
|
||||
42
cmake/FindPyosysEnv.cmake
Normal file
42
cmake/FindPyosysEnv.cmake
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# We need a *third* `FindPython`-style call in this codebase because the host
|
||||
# `Python3_EXECUTABLE` may not have pybind11 and cxxheaderparser installed,
|
||||
# and installing it can be onerous. To work around this problem we try to detect
|
||||
# whether the host interpreter has the necessary dependencies first, and if it
|
||||
# does not, fall back to using `uv`.
|
||||
|
||||
foreach (strategy host uv fail)
|
||||
if (strategy STREQUAL "host")
|
||||
set(PyosysEnv_PYTHON Python3_EXECUTABLE)
|
||||
elseif (strategy STREQUAL "uv")
|
||||
set(PyosysEnv_PYTHON uv run --no-project --with pybind11>3,<4 --with cxxheaderparser python)
|
||||
else()
|
||||
set(PyosysEnv_PYTHON)
|
||||
break()
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${PyosysEnv_PYTHON} -m pybind11 --includes
|
||||
RESULT_VARIABLE result
|
||||
OUTPUT_VARIABLE output
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
if (result EQUAL 0)
|
||||
string(REGEX REPLACE " ?-I" ";" pybind11_INCLUDE_DIR "${output}")
|
||||
list(FILTER pybind11_INCLUDE_DIR INCLUDE REGEX "/pybind11/")
|
||||
|
||||
execute_process(
|
||||
COMMAND ${PyosysEnv_PYTHON} ${CMAKE_SOURCE_DIR}/pyosys/generator.py --help
|
||||
RESULT_VARIABLE result
|
||||
OUTPUT_QUIET
|
||||
ERROR_QUIET
|
||||
)
|
||||
if (result EQUAL 0)
|
||||
break()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
find_package_handle_standard_args(PyosysEnv
|
||||
REQUIRED_VARS PyosysEnv_PYTHON pybind11_INCLUDE_DIR
|
||||
)
|
||||
16
cmake/FindPython3Embed.cmake
Normal file
16
cmake/FindPython3Embed.cmake
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Wrapper to improve behavior of `FindPython3` during cross-compilation.
|
||||
# Does not entirely fix the problem; CMake 4.0 introduces `Python_ARTIFACTS_PREFIX`, which will.
|
||||
|
||||
# Stash the package found status
|
||||
get_property(packages_found GLOBAL PROPERTY PACKAGES_FOUND)
|
||||
get_property(packages_not_found GLOBAL PROPERTY PACKAGES_NOT_FOUND)
|
||||
get_property(required_version GLOBAL PROPERTY _CMAKE_Python3_REQUIRED_VERSION)
|
||||
|
||||
# The `EXACT` specifier prevents the situation of `FindPython3` discovering a newer libpython-dev
|
||||
# than the interpreter found in the past, rejecting it because it is too new, and giving up.
|
||||
find_package(Python3 EXACT ${Python3_VERSION} COMPONENTS Development.Embed)
|
||||
set(Python3Embed_FOUND ${Python3_Development.Embed_FOUND})
|
||||
|
||||
set_property(GLOBAL PROPERTY PACKAGES_FOUND "${packages_found}")
|
||||
set_property(GLOBAL PROPERTY PACKAGES_NOT_FOUND "${packages_not_found}")
|
||||
set_property(GLOBAL PROPERTY _CMAKE_Python3_REQUIRED_VERSION "${required_version}")
|
||||
43
cmake/PkgConfig.cmake
Normal file
43
cmake/PkgConfig.cmake
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# Syntax:
|
||||
#
|
||||
# pkg_config_import(<package>)
|
||||
#
|
||||
# To use this command, `find_package(PkgConfig)` must be used beforehand, but it does
|
||||
# not have to succeed. If the `PkgConfig` package is not found, all imports silently fail.
|
||||
#
|
||||
# Imports `<package>` as a CMake `IMPORTED` target `PkgConfig::<package>`.
|
||||
# Updates the global `PACKAGES_FOUND` and `PACKAGES_NOT_FOUND` properties and defines
|
||||
# the `<package>_FOUND` variable.
|
||||
#
|
||||
function(pkg_config_import arg_PREFIX)
|
||||
cmake_parse_arguments(PARSE_ARGV 1 arg "" "" "MODULES")
|
||||
if (NOT arg_MODULES)
|
||||
set(arg_MODULES ${arg_PREFIX})
|
||||
endif()
|
||||
|
||||
if (PkgConfig_FOUND)
|
||||
# Once CMake 4.1 is available, this call should be replaced with `cmake_pkg_config()`.
|
||||
pkg_check_modules(${arg_PREFIX} IMPORTED_TARGET ${arg_MODULES})
|
||||
if (${arg_PREFIX}_FOUND)
|
||||
# We found the pkgconfig file, but is it actually a usable package?
|
||||
# The main cause of failure here would be cross-compiling, which pkg-config does not
|
||||
# handle very well (especially pre-`cmake_pkg_config()`).
|
||||
try_compile(is_usable
|
||||
SOURCE_FROM_CONTENT "main.cc" "int main() {}"
|
||||
LINK_LIBRARIES PkgConfig::${arg_PREFIX}
|
||||
LOG_DESCRIPTION "Checking if PkgConfig::${arg_PREFIX} is usable"
|
||||
)
|
||||
if (NOT is_usable)
|
||||
message(STATUS "Modules '${arg_MODULES}' unusable (bad \$PKG_CONFIG_LIBDIR?)")
|
||||
set(${arg_PREFIX}_FOUND 0)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (${arg_PREFIX}_FOUND)
|
||||
set_property(GLOBAL APPEND PROPERTY PACKAGES_FOUND ${arg_PREFIX})
|
||||
else()
|
||||
set_property(GLOBAL APPEND PROPERTY PACKAGES_NOT_FOUND ${arg_PREFIX})
|
||||
endif()
|
||||
return (PROPAGATE ${arg_PREFIX}_FOUND)
|
||||
endfunction()
|
||||
60
cmake/PmgenCommand.cmake
Normal file
60
cmake/PmgenCommand.cmake
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# Syntax:
|
||||
#
|
||||
# pmgen_command(<output>
|
||||
# [<input>...]
|
||||
# [PREFIX <prefix>]
|
||||
# [DEBUG]
|
||||
# )
|
||||
#
|
||||
# Builds `<output>_pm.h` in the current binary directory from pmgen source files `<input>`, which must have
|
||||
# the `*.pmg` extension. If `<input>...` contains more than one file, `<prefix>` must be provided.
|
||||
#
|
||||
# Defines the following variables:
|
||||
# - `PMGEN_<output>_DEFINED`: Boolean indicating whether this command was successfully invoked.
|
||||
# - `PMGEN_<output>_OUTPUT`: The header file generated by `pmgen`.
|
||||
#
|
||||
# Usage example:
|
||||
#
|
||||
# pmgen_command(my_dsp
|
||||
# my_dsp.pmg
|
||||
# )
|
||||
# yosys_pass(my_dsp
|
||||
# my_dsp.cc
|
||||
# ${PMGEN_my_dsp_OUTPUT}
|
||||
# )
|
||||
#
|
||||
# Usage example with multiple files:
|
||||
#
|
||||
# pmgen_command(my_dsp
|
||||
# my_dsp_macc.pmg
|
||||
# my_dsp_carry.pmg
|
||||
# PREFIX
|
||||
# my_dsp
|
||||
# )
|
||||
#
|
||||
function(pmgen_command arg_NAME)
|
||||
cmake_parse_arguments(PARSE_ARGV 1 arg "DEBUG" "PREFIX" "")
|
||||
set(arg_INPUTS ${arg_UNPARSED_ARGUMENTS})
|
||||
|
||||
set(pmgen_script ${CMAKE_SOURCE_DIR}/passes/pmgen/pmgen.py)
|
||||
set(pmgen_output ${CMAKE_CURRENT_BINARY_DIR}/${arg_NAME}_pm.h)
|
||||
cmake_path(RELATIVE_PATH pmgen_output BASE_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_VARIABLE pmgen_output_rel)
|
||||
add_custom_command(
|
||||
DEPENDS ${pmgen_script} ${arg_INPUTS}
|
||||
OUTPUT ${pmgen_output}
|
||||
COMMAND ${Python3_EXECUTABLE}
|
||||
${pmgen_script}
|
||||
"$<$<BOOL:${arg_DEBUG}>:-g>"
|
||||
"$<$<BOOL:${arg_PREFIX}>:-p;${arg_PREFIX}>"
|
||||
-o ${pmgen_output}
|
||||
${arg_INPUTS}
|
||||
COMMAND_EXPAND_LISTS
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
VERBATIM
|
||||
COMMENT "Compiling pattern matcher ${pmgen_output_rel}"
|
||||
)
|
||||
|
||||
# The usage of this command is somewhat inspired by `flex_target()` and `bison_target()`.
|
||||
set(PMGEN_${arg_NAME}_DEFINED TRUE)
|
||||
set(PMGEN_${arg_NAME}_OUTPUT ${pmgen_output} PARENT_SCOPE)
|
||||
endfunction()
|
||||
96
cmake/YosysAbc.cmake
Normal file
96
cmake/YosysAbc.cmake
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
include(CheckCompilerFlag)
|
||||
|
||||
define_property(TARGET PROPERTY YOSYS_IS_ABC)
|
||||
|
||||
function(target_safe_compile_options target scope)
|
||||
foreach (lang C CXX)
|
||||
foreach (flag ${ARGN})
|
||||
check_compiler_flag(${lang} ${flag} HAVE_${lang}_${flag})
|
||||
if (HAVE_${lang}_${flag})
|
||||
target_compile_options(${target} ${scope} $<$<COMPILE_LANGUAGE:${lang}>:${flag}>)
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
function(_yosys_abc_extract_makefile result vardecl filename)
|
||||
# Parse a Makefile fragment and extracts the first matching variable assignment into
|
||||
# a list of values.
|
||||
file(READ ${filename} contents)
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${filename})
|
||||
if ("${contents}" MATCHES "${vardecl}(\\\\\n|[ \t])*(([^\\\\\n]|\\\\\n)+)")
|
||||
string(REGEX REPLACE "(\\\\\n|[ \t])+" ";" ${result} "${CMAKE_MATCH_2}")
|
||||
endif()
|
||||
return (PROPAGATE ${result})
|
||||
endfunction()
|
||||
|
||||
function(yosys_abc_target arg_LIBNAME arg_EXENAME)
|
||||
cmake_parse_arguments(PARSE_ARGV 2 arg "" "INCLUDE_IN_ALL_IF" "")
|
||||
|
||||
# Instead of using either the ABC Make or CMake build system, we parse the source
|
||||
# of truth: ABC's `module.make` files. This turns out to be quite trivial.
|
||||
# This way, no assumptions about the environment are made, and Yosys can be compiled
|
||||
# on Windows without MSYS as a result (while benefitting other platforms as well).
|
||||
set(all_sources)
|
||||
_yosys_abc_extract_makefile(module_files "MODULES :=" ${CMAKE_SOURCE_DIR}/abc/Makefile)
|
||||
_yosys_abc_extract_makefile(module_files_cudd "MODULES \\+=" ${CMAKE_SOURCE_DIR}/abc/Makefile)
|
||||
list(REMOVE_ITEM module_files "$(wildcard" "src/ext*)")
|
||||
foreach (module_file ${module_files} ${module_files_cudd})
|
||||
_yosys_abc_extract_makefile(module_sources "SRC \\+=" ${CMAKE_SOURCE_DIR}/abc/${module_file}/module.make)
|
||||
list(APPEND all_sources ${module_sources})
|
||||
endforeach()
|
||||
list(TRANSFORM all_sources PREPEND abc/)
|
||||
|
||||
# Required to get `-DABC_NAMESPACE` below to work consistently.
|
||||
set_source_files_properties(${all_sources} PROPERTIES LANGUAGE CXX)
|
||||
|
||||
set(main_source abc/src/base/main/main.c)
|
||||
list(REMOVE_ITEM all_sources ${main_source})
|
||||
|
||||
find_package(Threads)
|
||||
yosys_cxx_library(${arg_LIBNAME} STATIC
|
||||
OUTPUT_NAME ${arg_LIBNAME}
|
||||
)
|
||||
target_sources(${arg_LIBNAME} PRIVATE ${all_sources})
|
||||
target_include_directories(${arg_LIBNAME} PRIVATE abc/src)
|
||||
target_compile_definitions(${arg_LIBNAME} PUBLIC
|
||||
WIN32_NO_DLL
|
||||
ABC_NAMESPACE=abc
|
||||
ABC_USE_STDINT_H=1
|
||||
ABC_USE_CUDD=1
|
||||
ABC_NO_DYNAMIC_LINKING
|
||||
$<${YOSYS_ENABLE_THREADS}:ABC_USE_PTHREADS>
|
||||
$<${YOSYS_ENABLE_READLINE}:ABC_USE_READLINE>
|
||||
ABC_NO_RLIMIT
|
||||
)
|
||||
target_safe_compile_options(${arg_LIBNAME} PRIVATE
|
||||
-fpermissive
|
||||
-fno-exceptions
|
||||
-Wno-write-strings
|
||||
-Wno-changes-meaning
|
||||
-Wno-attributes
|
||||
-Wno-deprecated-declarations
|
||||
-Wno-deprecated-comma-subscript
|
||||
-Wno-format
|
||||
-Wno-constant-logical-operand
|
||||
)
|
||||
target_link_libraries(${arg_LIBNAME} PUBLIC
|
||||
$<${YOSYS_ENABLE_THREADS}:Threads::Threads>
|
||||
$<${YOSYS_ENABLE_READLINE}:PkgConfig::readline>
|
||||
$<$<BOOL:${WIN32}>:-lshlwapi>
|
||||
)
|
||||
set_target_properties(${arg_LIBNAME} PROPERTIES
|
||||
YOSYS_IS_ABC ON
|
||||
)
|
||||
|
||||
yosys_cxx_executable(${arg_EXENAME}
|
||||
OUTPUT_NAME ${arg_EXENAME}
|
||||
INCLUDE_IN_ALL_IF "${arg_INCLUDE_IN_ALL_IF}"
|
||||
)
|
||||
target_sources(${arg_EXENAME} PRIVATE ${main_source})
|
||||
target_include_directories(${arg_EXENAME} PRIVATE abc/src)
|
||||
target_link_libraries(${arg_EXENAME} PRIVATE ${arg_LIBNAME})
|
||||
set_target_properties(${arg_EXENAME} PROPERTIES
|
||||
YOSYS_IS_ABC ON
|
||||
)
|
||||
endfunction()
|
||||
64
cmake/YosysAbcSubmodule.cmake
Normal file
64
cmake/YosysAbcSubmodule.cmake
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# depends on YosysVersion.cmake
|
||||
|
||||
function(yosys_check_abc_submodule)
|
||||
yosys_call_git(status)
|
||||
set(yosys_status "tarball")
|
||||
if (git_result EQUAL 0)
|
||||
set(yosys_status "git")
|
||||
endif()
|
||||
|
||||
yosys_call_git(submodule status abc)
|
||||
set(git_commit)
|
||||
if (EXISTS "${CMAKE_SOURCE_DIR}/abc/.gitcommit")
|
||||
file(READ "${CMAKE_SOURCE_DIR}/abc/.gitcommit" git_commit)
|
||||
string(STRIP "${git_commit}" git_commit)
|
||||
endif()
|
||||
set(abc_status "none")
|
||||
if (git_result EQUAL 0 AND git_output MATCHES "^ ")
|
||||
set(abc_status "git")
|
||||
elseif (git_result EQUAL 0 AND git_output MATCHES "^\\+")
|
||||
set(abc_status "git-changed")
|
||||
elseif (git_result EQUAL 0 AND git_output MATCHES "^U")
|
||||
set(abc_status "git-conflict")
|
||||
elseif (git_commit MATCHES "^[0-9a-fA-F]+$")
|
||||
set(abc_status "tarball")
|
||||
elseif (git_commit MATCHES "\\$Format:%[hH]\\$")
|
||||
set(abc_status "unknown")
|
||||
endif()
|
||||
|
||||
if (abc_status STREQUAL "git" OR abc_status STREQUAL "tarball")
|
||||
# Normal submodule or a tarball.
|
||||
elseif (abc_status STREQUAL "git-changed")
|
||||
message(FATAL_ERROR
|
||||
"'abc' submodule does not match expected commit.\n"
|
||||
"Run 'git submodule update' to check out the correct version.\n"
|
||||
"Note: If testing a different version of ABC, call 'git commit abc' "
|
||||
"in the Yosys source directory to update the expected commit.\n"
|
||||
)
|
||||
elseif (abc_status STREQUAL "git-conflict")
|
||||
message(FATAL_ERROR
|
||||
"'abc' submodule has merge conflicts.\n"
|
||||
"Please resolve merge conflicts before continuing.\n"
|
||||
)
|
||||
elseif (abc_status STREQUAL "unknown") # OK
|
||||
message(FATAL_ERROR
|
||||
"Error: 'abc' is not configured as a git submodule.\n"
|
||||
"To resolve this:\n"
|
||||
"1. Back up your changes: Save any modifications from the 'abc' directory to another location.\n"
|
||||
"2. Remove the existing 'abc' directory: Delete the 'abc' directory and all its contents.\n"
|
||||
"3. Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule.\n"
|
||||
"4. Reapply your changes: Move your saved changes back to the 'abc' directory, if necessary.\n"
|
||||
)
|
||||
elseif (yosys_status STREQUAL "git") # OK
|
||||
message(FATAL_ERROR
|
||||
"Initialize the submodule: Run 'git submodule update --init' to set up 'abc' as a submodule.\n"
|
||||
)
|
||||
else() #
|
||||
message(FATAL_ERROR
|
||||
"${CMAKE_SOURCE_DIR} is not configured as a git repository, and 'abc' folder is missing.\n"
|
||||
"If you already have ABC, set 'ABCEXTERNAL' make variable to point to ABC executable.\n"
|
||||
"Otherwise, download release archive 'yosys.tar.gz' from https://github.com/YosysHQ/yosys/releases.\n"
|
||||
" ('Source code' archive does not contain submodules.)\n"
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
321
cmake/YosysComponent.cmake
Normal file
321
cmake/YosysComponent.cmake
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
set(namespace "yosys")
|
||||
|
||||
# Properties internal to the component system.
|
||||
define_property(TARGET PROPERTY YOSYS_COMPONENT)
|
||||
define_property(TARGET PROPERTY YOSYS_PROVIDES)
|
||||
define_property(TARGET PROPERTY YOSYS_REQUIRES)
|
||||
define_property(TARGET PROPERTY YOSYS_DATA_FILES)
|
||||
define_property(TARGET PROPERTY YOSYS_ENABLE_IF)
|
||||
|
||||
# Syntax:
|
||||
#
|
||||
# yosys_component(<prefix> <name> [INTERFACE]
|
||||
# [<source>...]
|
||||
# [DEFINITIONS <definition>...]
|
||||
# [INCLUDE_DIRS <directory>...]
|
||||
# [LIBRARIES <library>...]
|
||||
# [PROVIDES <provided>...]
|
||||
# [REQUIRES <required>...]
|
||||
# [DATA_DIR <data_dir>]
|
||||
# [DATA_FILES <data_file>...]
|
||||
# [DATA_EXPLICIT [<dest_file> <src_file>]...]
|
||||
# [ESSENTIAL]
|
||||
# [ENABLE_IF "<condition>"]
|
||||
# )
|
||||
#
|
||||
# Creates a target `yosys_<name>` (if `<prefix>` is empty) or `yosys_<prefix>_<name>` (if `<prefix>` is not empty).
|
||||
# This target is an library target with some Yosys-specific behavior that simplifies partitioning the compiler
|
||||
# into small pieces with explicitly defined compile-time and run-time dependency metadata. Circular dependencies
|
||||
# between compilation units in different components are allowed.
|
||||
#
|
||||
# Parameter description:
|
||||
# - `INTERFACE` should be specified for header-only libraries.
|
||||
# - `<source>...` is a shortcut for `target_sources(PRIVATE)`.
|
||||
# - `DEFINITIONS <definition>...` is a shortcut for `target_compile_definitions(PRIVATE)`.
|
||||
# - `INCLUDE_DIRS <directory>...` is a shortcut for `target_include_directories(PRIVATE)`.
|
||||
# - `LIBRARIES <library>...` is a shortcut for `target_link_libraries(PRIVATE)`.
|
||||
# - `PROVIDES <provided>...` creates aliases to each `<provided>` component name.
|
||||
# - `REQUIRES <required>...` ensures that if this target is linked into the Yosys binary, then every
|
||||
# `<required>` component is also linked in.
|
||||
# - `DATA_DIR <data_dir>` configures a base directory for installing data files; this directory
|
||||
# is (relative to the root build directory or the installation prefix) `share/<data_dir>` if
|
||||
# `DATA_DIR` is provided, and `share` if not.
|
||||
# - `DATA_FILES <data_file>...` installs each of `<data_file>` as `share/<data_dir>/<path>/<name>`,
|
||||
# where `<path>` is the directory name of `<data_file>` and `<name>` is the filename of `<data_file>`.
|
||||
# - `DATA_EXPLICIT [<dest_file> <src_file>]...` installs each `<src_file>` as `share/<data_dir>/<dest_file>`.
|
||||
# Where possible, `DATA_FILES` should be used instead.
|
||||
# - `ESSENTIAL` ensures that this target is always linked into the Yosys binary.
|
||||
# - `ENABLE_IF "<condition>"` marks the component as available only when `if(<condition>)` would run.
|
||||
#
|
||||
# Avoid using this function directly. Instead, use one of the wrappers below as follows:
|
||||
# - to define a normal pass, use `yosys_pass(<name>)` to add a component called `<name>`.
|
||||
# - to define a test pass, use `yosys_test_pass(<name>)` to add a component called `test_<name>`.
|
||||
# - to define a frontend, use `yosys_frontend(<name>)` to add a component called `read_<name>`.
|
||||
# - to define a backend, use `yosys_backend(<name>)` to add a component called `write_<name>`.
|
||||
# - if the component sources define more than one pass, use `PROVIDES` with names of the other passes.
|
||||
# - if the component uses `Pass::call()`, `Frontend::frontend_call()`, `Backend::backend_call()`, or other
|
||||
# similar functions, use `REQUIRES` with names of all possibly needed passes.
|
||||
# - if the component needs an essential pass, add the latter to `REQUIRES` anyway for completeness.
|
||||
# - if the component subclasses a `ScriptPass`, build Yosys, then run `misc/script_pass_depends.py <pass>`
|
||||
# to extract the names of all referenced passes.
|
||||
# - in general, component names should be the same as corresponding pass names (as used in the REPL),
|
||||
# but this is not a hard requirement and any suitable name can be used if desired.
|
||||
#
|
||||
function(yosys_component arg_PREFIX arg_NAME)
|
||||
cmake_parse_arguments(PARSE_ARGV 2 arg
|
||||
"INTERFACE;ESSENTIAL;BOOTSTRAP"
|
||||
"DATA_DIR;ENABLE_IF"
|
||||
"DEFINITIONS;INCLUDE_DIRS;LIBRARIES;DATA_FILES;DATA_EXPLICIT;PROVIDES;REQUIRES"
|
||||
)
|
||||
set(arg_SOURCES ${arg_UNPARSED_ARGUMENTS})
|
||||
if ("${arg_ENABLE_IF}" STREQUAL "")
|
||||
set(arg_ENABLE_IF TRUE)
|
||||
endif()
|
||||
|
||||
if (arg_PREFIX STREQUAL "")
|
||||
set(component "${arg_NAME}")
|
||||
else()
|
||||
set(component "${arg_PREFIX}_${arg_NAME}")
|
||||
endif()
|
||||
set(target "${namespace}_${component}")
|
||||
list(TRANSFORM arg_PROVIDES PREPEND ${namespace}_ OUTPUT_VARIABLE provides_targets)
|
||||
|
||||
# An OBJECT library is used to allow for circular symbol dependencies between any source files.
|
||||
# Unfortunately, public dependencies between OBJECT libraries aren't handled correctly, so we have
|
||||
# to do it ourselves.
|
||||
if (arg_SOURCES AND NOT arg_INTERFACE)
|
||||
add_library(${target} EXCLUDE_FROM_ALL OBJECT)
|
||||
target_sources(${target} PRIVATE ${arg_SOURCES})
|
||||
target_include_directories(${target} PRIVATE ${arg_INCLUDE_DIRS})
|
||||
target_compile_definitions(${target} PRIVATE ${arg_DEFINITIONS})
|
||||
target_link_libraries(${target} PUBLIC yosys_common ${arg_LIBRARIES})
|
||||
foreach (alias ${provides_targets})
|
||||
add_library(${alias} ALIAS ${target})
|
||||
endforeach()
|
||||
else()
|
||||
add_library(${target} EXCLUDE_FROM_ALL INTERFACE)
|
||||
endif()
|
||||
set_target_properties(${target} PROPERTIES
|
||||
YOSYS_COMPONENT YES
|
||||
YOSYS_PROVIDES "${arg_PROVIDES}"
|
||||
YOSYS_REQUIRES "${arg_REQUIRES}"
|
||||
YOSYS_DATA_FILES ""
|
||||
YOSYS_ENABLE_IF "${arg_ENABLE_IF}"
|
||||
)
|
||||
|
||||
set(share_file_pairs)
|
||||
foreach (share_file ${arg_DATA_FILES})
|
||||
list(APPEND share_file_pairs ${share_file} ${share_file})
|
||||
endforeach()
|
||||
list(APPEND share_file_pairs ${arg_DATA_EXPLICIT})
|
||||
if (share_file_pairs)
|
||||
set(data_depends)
|
||||
set(share_root ${CMAKE_BINARY_DIR}/share)
|
||||
while (share_file_pairs)
|
||||
list(LENGTH share_file_pairs share_file_unpaired)
|
||||
if (share_file_unpaired EQUAL 1)
|
||||
message(FATAL_ERROR "Unpaired DATA_EXPLICIT argument: ${share_file_pairs}")
|
||||
endif()
|
||||
list(POP_FRONT share_file_pairs dst_file src_file)
|
||||
cmake_path(ABSOLUTE_PATH src_file BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(out_dir ${arg_DATA_DIR})
|
||||
cmake_path(GET dst_file PARENT_PATH dst_parent)
|
||||
cmake_path(APPEND out_dir ${dst_parent})
|
||||
cmake_path(GET dst_file FILENAME dst_filename)
|
||||
cmake_path(APPEND out_dir ${dst_filename} OUTPUT_VARIABLE out_file)
|
||||
file(MAKE_DIRECTORY ${share_root}/${out_dir})
|
||||
add_custom_command(
|
||||
DEPENDS ${src_file}
|
||||
OUTPUT ${share_root}/${out_file}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src_file} ${share_root}/${out_file}
|
||||
VERBATIM
|
||||
COMMENT "Copying share/${out_file}"
|
||||
)
|
||||
set_property(TARGET ${target} APPEND PROPERTY YOSYS_DATA_FILES ${out_file})
|
||||
list(APPEND data_depends ${share_root}/${out_file})
|
||||
endwhile()
|
||||
add_custom_target(${target}-data DEPENDS ${data_depends})
|
||||
add_dependencies(${target} ${target}-data)
|
||||
endif()
|
||||
|
||||
if (NOT arg_BOOTSTRAP)
|
||||
set_property(TARGET yosys_everything APPEND PROPERTY YOSYS_REQUIRES ${component})
|
||||
if (arg_ESSENTIAL)
|
||||
set_property(TARGET yosys_essentials APPEND PROPERTY YOSYS_REQUIRES ${component})
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Syntax:
|
||||
#
|
||||
# yosys_core(<name> [<option>...]) →
|
||||
# yosys_component("" <name> [<option>...])
|
||||
#
|
||||
# yosys_pass(<name> [<option>...]) →
|
||||
# yosys_component("" <name> [<option>...])
|
||||
#
|
||||
# yosys_test_pass(<name> [<option>...]) →
|
||||
# yosys_component("test" <name> [<option>...])
|
||||
#
|
||||
# yosys_frontend(<name> [<option>...]) →
|
||||
# yosys_component("frontend" <name> [<option>...])
|
||||
#
|
||||
# yosys_backend(<name> [<option>...]) →
|
||||
# yosys_component("backend" <name> [<option>...])
|
||||
#
|
||||
# See `yosys_component()` for details.
|
||||
#
|
||||
function(yosys_core)
|
||||
yosys_component("" ${ARGV})
|
||||
endfunction()
|
||||
|
||||
function(yosys_pass)
|
||||
yosys_component("" ${ARGV})
|
||||
endfunction()
|
||||
|
||||
function(yosys_test_pass)
|
||||
yosys_component(test ${ARGV})
|
||||
endfunction()
|
||||
|
||||
function(yosys_frontend)
|
||||
yosys_component(read ${ARGV})
|
||||
endfunction()
|
||||
|
||||
function(yosys_backend)
|
||||
yosys_component(write ${ARGV})
|
||||
endfunction()
|
||||
|
||||
# Syntax:
|
||||
#
|
||||
# yosys_expand_components(<variable> <component>...)
|
||||
#
|
||||
# Populates `<variable>` with the list of components required for linking every `<component>`,
|
||||
# sorted by pre-order traversal.
|
||||
#
|
||||
function(yosys_expand_components arg_OUTPUT)
|
||||
cmake_parse_arguments(PARSE_ARGV 1 arg "QUIET" "" "")
|
||||
set(arg_COMPONENTS ${arg_UNPARSED_ARGUMENTS})
|
||||
|
||||
function(check_components context components)
|
||||
set(error 0)
|
||||
foreach (component ${components})
|
||||
set(target "${namespace}_${component}")
|
||||
if (NOT TARGET ${target})
|
||||
message(SEND_ERROR "${context}Target ${target} does not exist")
|
||||
set(error 1)
|
||||
continue()
|
||||
endif()
|
||||
get_target_property(target_is_component ${target} YOSYS_COMPONENT)
|
||||
if (NOT target_is_component)
|
||||
message(SEND_ERROR "${context}Target ${target} is not a Yosys component")
|
||||
set(error 1)
|
||||
endif()
|
||||
endforeach()
|
||||
return (PROPAGATE error)
|
||||
endfunction()
|
||||
|
||||
function(depth_first_search component visited_components required_components)
|
||||
list(APPEND visited_components ${component})
|
||||
get_target_property(component_requires "${namespace}_${component}" YOSYS_REQUIRES)
|
||||
check_components("In REQUIRES of ${component}: " "${component_requires}")
|
||||
foreach (requirement ${component_requires})
|
||||
if (NOT requirement IN_LIST visited_components)
|
||||
depth_first_search(${requirement} "${visited_components}" "${required_components}")
|
||||
endif()
|
||||
endforeach()
|
||||
list(APPEND required_components ${component})
|
||||
return (PROPAGATE visited_components required_components)
|
||||
endfunction()
|
||||
|
||||
set(visited_components)
|
||||
set(required_components)
|
||||
check_components("" "${arg_COMPONENTS}")
|
||||
foreach (component ${arg_COMPONENTS})
|
||||
if (NOT component IN_LIST visited_components)
|
||||
depth_first_search(${component} "${visited_components}" "${required_components}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# If `everything` is in the component list, ignore disabled dependencies, else fail the build.
|
||||
set(fail_if_disabled TRUE)
|
||||
if (everything IN_LIST arg_COMPONENTS)
|
||||
set(fail_if_disabled FALSE)
|
||||
endif()
|
||||
|
||||
# ${required_components} are now sorted in pre-order (every component is visited before
|
||||
# all of its dependents). Figure out which components are enabled and which components
|
||||
# have disabled dependencies.
|
||||
set(enabled_components)
|
||||
if (NOT arg_QUIET)
|
||||
message(TRACE "Resolving component dependencies:")
|
||||
endif()
|
||||
foreach (component ${required_components})
|
||||
set(why_disabled "")
|
||||
get_target_property(component_enable_if "${namespace}_${component}" YOSYS_ENABLE_IF)
|
||||
if (${component_enable_if})
|
||||
get_target_property(component_requires "${namespace}_${component}" YOSYS_REQUIRES)
|
||||
foreach (requirement ${component_requires})
|
||||
if (NOT requirement IN_LIST enabled_components)
|
||||
set(why_disabled "dependency ${requirement}")
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
else()
|
||||
set(why_disabled "condition")
|
||||
endif()
|
||||
if ("${why_disabled}" STREQUAL "")
|
||||
list(APPEND enabled_components ${component})
|
||||
if (NOT arg_QUIET)
|
||||
message(TRACE " Component ${component} enabled")
|
||||
endif()
|
||||
else()
|
||||
if (NOT arg_QUIET)
|
||||
message(TRACE " Component ${component} disabled (cause: ${why_disabled})")
|
||||
endif()
|
||||
if (fail_if_disabled)
|
||||
message(FATAL_ERROR "Required component ${component} is disabled (cause: ${why_disabled})")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(${arg_OUTPUT} ${enabled_components})
|
||||
return(PROPAGATE ${arg_OUTPUT})
|
||||
endfunction()
|
||||
|
||||
# Syntax:
|
||||
#
|
||||
# yosys_link_components(<target> {INTERFACE|PUBLIC|PRIVATE} <component>...)
|
||||
#
|
||||
# Link every `<component>` into `<target>`.
|
||||
#
|
||||
function(yosys_link_components arg_TARGET arg_SCOPE)
|
||||
cmake_parse_arguments(PARSE_ARGV 2 arg "" "" "")
|
||||
set(arg_COMPONENTS ${arg_UNPARSED_ARGUMENTS})
|
||||
|
||||
message(VERBOSE "Components for ${arg_TARGET}: ${arg_COMPONENTS}")
|
||||
list(TRANSFORM arg_COMPONENTS PREPEND ${namespace}_ OUTPUT_VARIABLE linked_targets)
|
||||
target_link_libraries(${arg_TARGET} ${arg_SCOPE} ${linked_targets})
|
||||
endfunction()
|
||||
|
||||
# Syntax:
|
||||
#
|
||||
# yosys_install_component_data(<component>... DESTINATION <directory>)
|
||||
#
|
||||
# Install data files for every `<component>` into `<directory>`.
|
||||
# Equivalent to copying `${CMAKE_BINARY_DIR}/share/.` to `<directory>/.` after a clean rebuild.
|
||||
#
|
||||
function(yosys_install_component_data)
|
||||
cmake_parse_arguments(PARSE_ARGV 0 arg "" "DESTINATION" "")
|
||||
set(arg_COMPONENTS ${arg_UNPARSED_ARGUMENTS})
|
||||
if (NOT arg_DESTINATION)
|
||||
message(FATAL_ERROR "Missing DESTINATION argument")
|
||||
endif()
|
||||
|
||||
foreach (component ${arg_COMPONENTS})
|
||||
get_target_property(data_files ${namespace}_${component} YOSYS_DATA_FILES)
|
||||
foreach (data_file ${data_files})
|
||||
cmake_path(GET data_file PARENT_PATH data_dir)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/share/${data_file} DESTINATION ${arg_DESTINATION}/${data_dir})
|
||||
endforeach()
|
||||
endforeach()
|
||||
endfunction()
|
||||
60
cmake/YosysConfigScript.cmake
Normal file
60
cmake/YosysConfigScript.cmake
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# Syntax:
|
||||
#
|
||||
# yosys_config_script({BUILD|INSTALL})
|
||||
#
|
||||
# Generates a `yosys-config` executable with embedded paths for in-tree builds or after installation.
|
||||
#
|
||||
function(yosys_config_script scope)
|
||||
if (scope STREQUAL BUILD)
|
||||
set(BINDIR ${CMAKE_BINARY_DIR})
|
||||
set(LIBDIR ${CMAKE_BINARY_DIR})
|
||||
set(DATDIR ${CMAKE_BINARY_DIR}/share)
|
||||
set(suffix "")
|
||||
elseif (scope STREQUAL INSTALL)
|
||||
set(BINDIR ${YOSYS_INSTALL_FULL_BINDIR})
|
||||
set(LIBDIR ${YOSYS_INSTALL_FULL_LIBDIR})
|
||||
set(DATDIR ${YOSYS_INSTALL_FULL_DATADIR})
|
||||
set(suffix ".install")
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid scope ${scope}")
|
||||
endif()
|
||||
|
||||
set(platform_link_flags)
|
||||
set(platform_libs)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
set(platform_link_flags -undefined dynamic_lookup)
|
||||
endif()
|
||||
if (MINGW)
|
||||
set(platform_libs -l:yosys.exe.a)
|
||||
endif()
|
||||
|
||||
set(CXX ${CMAKE_CXX_COMPILER})
|
||||
string(JOIN " " CXXFLAGS
|
||||
-std=c++${CMAKE_CXX_STANDARD}
|
||||
${CMAKE_CXX_FLAGS}
|
||||
${CMAKE_CXX_COMPILE_OPTIONS_PIC}
|
||||
-D_YOSYS_
|
||||
"-DYOSYS_VER=\"${YOSYS_VERSION}\""
|
||||
"-DYOSYS_MAJOR=${YOSYS_VERSION_MAJOR}"
|
||||
"-DYOSYS_MINOR=${YOSYS_VERSION_MINOR}"
|
||||
"-DYOSYS_COMMIT=${YOSYS_VERSION_COMMIT}"
|
||||
-I${DATDIR}/include
|
||||
)
|
||||
string(JOIN " " LINKFLAGS
|
||||
${CMAKE_SHARED_LIBRARY_CXX_FLAGS}
|
||||
-L${LIBDIR}
|
||||
${platform_link_flags}
|
||||
)
|
||||
string(JOIN " " LIBS
|
||||
${platform_libs}
|
||||
)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/misc/yosys-config.in
|
||||
${YOSYS_PROGRAM_PREFIX}yosys-config${suffix}
|
||||
USE_SOURCE_PERMISSIONS
|
||||
@ONLY
|
||||
)
|
||||
if (scope STREQUAL INSTALL)
|
||||
install(PROGRAMS ${CMAKE_BINARY_DIR}/${YOSYS_PROGRAM_PREFIX}yosys-config
|
||||
DESTINATION ${YOSYS_INSTALL_BINDIR})
|
||||
endif()
|
||||
endfunction()
|
||||
9
cmake/YosysInstallDirs.cmake
Normal file
9
cmake/YosysInstallDirs.cmake
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
include(GNUInstallDirs)
|
||||
|
||||
# Nothing should be installed outside of the following locations.
|
||||
set(YOSYS_INSTALL_BINDIR ${CMAKE_INSTALL_BINDIR})
|
||||
set(YOSYS_INSTALL_FULL_BINDIR ${CMAKE_INSTALL_FULL_BINDIR})
|
||||
set(YOSYS_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}/${YOSYS_PROGRAM_PREFIX}yosys)
|
||||
set(YOSYS_INSTALL_FULL_LIBDIR ${CMAKE_INSTALL_FULL_LIBDIR}/${YOSYS_PROGRAM_PREFIX}yosys)
|
||||
set(YOSYS_INSTALL_DATADIR ${CMAKE_INSTALL_DATADIR}/${YOSYS_PROGRAM_PREFIX}yosys)
|
||||
set(YOSYS_INSTALL_FULL_DATADIR ${CMAKE_INSTALL_FULL_DATADIR}/${YOSYS_PROGRAM_PREFIX}yosys)
|
||||
104
cmake/YosysLinkTarget.cmake
Normal file
104
cmake/YosysLinkTarget.cmake
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# Syntax:
|
||||
#
|
||||
# yosys_cxx_library(<target> {SHARED|STATIC}
|
||||
# OUTPUT_NAME <name>
|
||||
# [INCLUDE_IN_ALL | INCLUDE_IN_ALL_IF <condition>]
|
||||
# )
|
||||
#
|
||||
# Creates a libary target `<target>` with `SHARED` or `STATIC` scope called `<name>` (or `<target>` if
|
||||
# not specified), placed in the root of the build directory and prefixed with `${YOSYS_PROGRAM_PREFIX}`.
|
||||
# Target is built by default and installed only if `<condition>` (an `if()` expression) is true.
|
||||
#
|
||||
function(yosys_cxx_library arg_TARGET arg_SCOPE)
|
||||
cmake_parse_arguments(PARSE_ARGV 2 arg "INCLUDE_IN_ALL" "OUTPUT_NAME;INCLUDE_IN_ALL_IF" "")
|
||||
if (NOT arg_OUTPUT_NAME)
|
||||
message(FATAL_ERROR "OUTPUT_NAME argument is mandatory")
|
||||
endif()
|
||||
set(include_in_all FALSE)
|
||||
if (arg_INCLUDE_IN_ALL)
|
||||
set(include_in_all TRUE)
|
||||
elseif (${arg_INCLUDE_IN_ALL_IF})
|
||||
set(include_in_all TRUE)
|
||||
endif()
|
||||
|
||||
add_library(${arg_TARGET} ${arg_SCOPE})
|
||||
set_target_properties(${arg_TARGET} PROPERTIES
|
||||
PREFIX "${YOSYS_PROGRAM_PREFIX}"
|
||||
OUTPUT_NAME "${arg_OUTPUT_NAME}"
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
if (include_in_all)
|
||||
install(TARGETS ${arg_TARGET} DESTINATION ${YOSYS_INSTALL_LIBDIR})
|
||||
else()
|
||||
set_target_properties(${arg_TARGET} PROPERTIES EXCLUDE_FROM_ALL TRUE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Syntax:
|
||||
#
|
||||
# yosys_cxx_executable(<target>
|
||||
# [OUTPUT_NAME <name>]
|
||||
# [INCLUDE_IN_ALL | INCLUDE_IN_ALL_IF <condition>]
|
||||
# )
|
||||
#
|
||||
# Creates an executable target `<target>` scope called `<name>` (or `<target>` if not specified), placed
|
||||
# in the root of the build directory and prefixed with `${YOSYS_PROGRAM_PREFIX}`. Target is built by
|
||||
# default and installed only if `INCLUDE_IN_ALL` is provided or `<condition>` (an `if()` expression) is true.
|
||||
#
|
||||
function(yosys_cxx_executable arg_TARGET)
|
||||
cmake_parse_arguments(PARSE_ARGV 1 arg "INCLUDE_IN_ALL" "OUTPUT_NAME;INCLUDE_IN_ALL_IF" "")
|
||||
if (NOT arg_OUTPUT_NAME)
|
||||
message(FATAL_ERROR "OUTPUT_NAME argument is mandatory")
|
||||
endif()
|
||||
set(include_in_all FALSE)
|
||||
if (arg_INCLUDE_IN_ALL)
|
||||
set(include_in_all TRUE)
|
||||
elseif (${arg_INCLUDE_IN_ALL_IF})
|
||||
set(include_in_all TRUE)
|
||||
endif()
|
||||
|
||||
add_executable(${arg_TARGET})
|
||||
set_target_properties(${arg_TARGET} PROPERTIES
|
||||
PREFIX "${YOSYS_PROGRAM_PREFIX}"
|
||||
OUTPUT_NAME "${arg_OUTPUT_NAME}"
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
if (include_in_all)
|
||||
install(TARGETS ${arg_TARGET} DESTINATION ${YOSYS_INSTALL_BINDIR})
|
||||
else()
|
||||
set_target_properties(${arg_TARGET} PROPERTIES EXCLUDE_FROM_ALL TRUE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Syntax:
|
||||
#
|
||||
# yosys_python_executable(<target> <source>)
|
||||
#
|
||||
# Installs Python script `<source>` as an executable in the standard binary directory, adding a launcher wrapper
|
||||
# if the platform requires it. Inside `<source>`, several substitutions are available:
|
||||
# - `@PYTHON_SHEBANG@` will be replaced with an appropriate shebang line (without the initial `#!`)
|
||||
# - `@YOSYS_PROGRAM_PREFIX@` will be replaced with the program prefix
|
||||
# - any other `@\w+@` tokens have unspecified behavior and must not be used
|
||||
#
|
||||
function(yosys_python_executable basename source)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL MSYS)
|
||||
execute_process(
|
||||
COMMAND cygpath -w -m ${CMAKE_INSTALL_BINDIR}/python3
|
||||
OUTPUT_VARIABLE PYTHON_SHEBANG
|
||||
COMMAND_ERROR_IS_FATAL ANY
|
||||
)
|
||||
|
||||
add_executable(${basename} ${CMAKE_SOURCE_DIR}/misc/launcher.c)
|
||||
target_compile_definitions(${basename} GUI=0)
|
||||
install(TARGETS ${basename} DESTINATION ${YOSYS_INSTALL_BINDIR})
|
||||
|
||||
set(scriptname ${CMAKE_BINARY_DIR}/${YOSYS_PROGRAM_PREFIX}${basename}-script.py)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${source} ${scriptname} @ONLY)
|
||||
install(FILES ${scriptname} DESTINATION ${YOSYS_INSTALL_BINDIR})
|
||||
else()
|
||||
set(PYTHON_SHEBANG "/usr/bin/env python3")
|
||||
set(scriptname ${CMAKE_BINARY_DIR}/${YOSYS_PROGRAM_PREFIX}${basename}${CMAKE_EXECUTABLE_SUFFIX})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${source} ${scriptname} USE_SOURCE_PERMISSIONS @ONLY)
|
||||
install(PROGRAMS ${scriptname} DESTINATION ${YOSYS_INSTALL_BINDIR})
|
||||
endif()
|
||||
endfunction()
|
||||
48
cmake/YosysVerific.cmake
Normal file
48
cmake/YosysVerific.cmake
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
if (APPLE)
|
||||
set(VERIFIC_LIB_SUFFIX -mac.a)
|
||||
elseif (LINUX)
|
||||
set(VERIFIC_LIB_SUFFIX -linux.a)
|
||||
elseif (WIN32)
|
||||
set(VERIFIC_LIB_SUFFIX -windows.a)
|
||||
else()
|
||||
set(VERIFIC_LIB_SUFFIX -NOTFOUND)
|
||||
endif()
|
||||
|
||||
# Syntax:
|
||||
#
|
||||
# get_verific_components(<result>)
|
||||
#
|
||||
# Assigns variable `<result>` to a list of Verific components detected in `${YOSYS_VERIFIC_DIR}`.
|
||||
#
|
||||
function(get_verific_components result)
|
||||
file(GLOB libraries
|
||||
RELATIVE ${YOSYS_VERIFIC_DIR}
|
||||
${YOSYS_VERIFIC_DIR}/*/*${VERIFIC_LIB_SUFFIX}
|
||||
)
|
||||
set(components)
|
||||
foreach (library ${libraries})
|
||||
cmake_path(GET library PARENT_PATH component)
|
||||
list(APPEND components ${component})
|
||||
endforeach()
|
||||
|
||||
set(${result} ${components})
|
||||
return(PROPAGATE ${result})
|
||||
endfunction()
|
||||
|
||||
# Syntax:
|
||||
#
|
||||
# get_verific_options(<include_dirs> <libraries> <components>...)
|
||||
#
|
||||
# Assigns variables `<include_dirs>` and `<libraries>` to lists required to use Verific
|
||||
# `<components>`.
|
||||
#
|
||||
function(get_verific_options include_dirs libraries)
|
||||
set(${include_dirs})
|
||||
set(${libraries})
|
||||
foreach (component ${ARGN})
|
||||
list(APPEND ${include_dirs} ${YOSYS_VERIFIC_DIR}/${component})
|
||||
list(APPEND ${libraries} ${YOSYS_VERIFIC_DIR}/${component}/${component}${VERIFIC_LIB_SUFFIX})
|
||||
endforeach()
|
||||
|
||||
return(PROPAGATE ${include_dirs} ${libraries})
|
||||
endfunction()
|
||||
162
cmake/YosysVersion.cmake
Normal file
162
cmake/YosysVersion.cmake
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
# Syntax:
|
||||
#
|
||||
# yosys_call_git(<args>...)
|
||||
#
|
||||
# Calls `git <args>...` in the project source directory. Never causes errors.
|
||||
#
|
||||
# Defines the following variables:
|
||||
# - `git_result`: exit code
|
||||
# - `git_output`: standard output (standard error is discarded)
|
||||
#
|
||||
function(yosys_call_git)
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} ${ARGV}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
RESULT_VARIABLE git_result
|
||||
OUTPUT_VARIABLE git_output
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
return(PROPAGATE git_result git_output)
|
||||
endfunction()
|
||||
|
||||
# Syntax:
|
||||
#
|
||||
# yosys_extract_version()
|
||||
#
|
||||
# Defines the following variables:
|
||||
# - `YOSYS_VERSION_MAJOR`: major version number
|
||||
# - `YOSYS_VERSION_MINOR`: minor version number
|
||||
# - `YOSYS_VERSION_COMMIT`: distance since release
|
||||
# - `YOSYS_VERSION`: either `<major>.<minor>+<distance>` or `<major>.<minor>+post`
|
||||
# - `YOSYS_CHECKOUT_INFO`: either `<abbrev>`, `<abbrev>-dirty`, or `UNKNOWN`
|
||||
# - `YOSYS_ORIGIN_INFO`: either `forge.tld/repo/user at branch` or ``
|
||||
#
|
||||
# For builds without git, it is possible to define `-DYOSYS_CHECKOUT_INFO=` and
|
||||
# `-DYOSYS_ORIGIN_INFO=` explicitly when configuring, which will be included in log output.
|
||||
#
|
||||
function(yosys_extract_version)
|
||||
# Version numbers are placed in an external file that can be easily rewritten.
|
||||
include(YosysVersionData)
|
||||
|
||||
# Extract git metadata if possible.
|
||||
set(git_distance "")
|
||||
set(git_abbrev "")
|
||||
set(git_dirty NO)
|
||||
set(git_origin "")
|
||||
set(git_branch "")
|
||||
find_package(Git QUIET)
|
||||
if (Git_FOUND)
|
||||
yosys_call_git(rev-parse --git-dir)
|
||||
if (git_result EQUAL 0)
|
||||
set(git_dir ${git_output})
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${git_dir}/HEAD)
|
||||
file(READ ${git_dir}/HEAD git_head)
|
||||
if (git_head MATCHES "^ref: (.+)\n$")
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${git_dir}/${CMAKE_MATCH_1})
|
||||
endif()
|
||||
yosys_call_git(rev-list --count v${YOSYS_VERSION_MAJOR}.${YOSYS_VERSION_MINOR}..HEAD)
|
||||
set(git_distance ${git_output})
|
||||
yosys_call_git(rev-parse --short=9 HEAD)
|
||||
set(git_abbrev ${git_output})
|
||||
yosys_call_git(diff --exit-code --quiet)
|
||||
set(git_dirty ${git_result})
|
||||
yosys_call_git(config --get remote.origin.url)
|
||||
set(git_origin ${git_output})
|
||||
yosys_call_git(rev-parse --abbrev-ref HEAD)
|
||||
set(git_branch ${git_output})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Build YOSYS_VERSION (just the version info).
|
||||
set(YOSYS_VERSION "${YOSYS_VERSION_MAJOR}.${YOSYS_VERSION_MINOR}")
|
||||
if (git_distance STREQUAL "")
|
||||
string(APPEND YOSYS_VERSION "+post")
|
||||
else()
|
||||
set(YOSYS_VERSION_COMMIT ${git_distance})
|
||||
if (NOT git_distance EQUAL 0)
|
||||
string(APPEND YOSYS_VERSION "+${git_distance}")
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Configuring Yosys ${YOSYS_VERSION}")
|
||||
|
||||
if (NOT YOSYS_CHECKOUT_INFO)
|
||||
# Build YOSYS_CHECKOUT_INFO (git sha1 and dirty status).
|
||||
if (git_abbrev STREQUAL "")
|
||||
# No git checkout, see if the tarball was created with `git archive`.
|
||||
file(READ ${CMAKE_SOURCE_DIR}/.gitcommit git_abbrev)
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/.gitcommit)
|
||||
string(STRIP "${git_abbrev}" git_abbrev)
|
||||
if (git_abbrev MATCHES "Format:")
|
||||
# No substitutions, we're out of options.
|
||||
set(YOSYS_CHECKOUT_INFO UNKNOWN)
|
||||
else()
|
||||
# Substitutions were made, good.
|
||||
set(YOSYS_CHECKOUT_INFO ${git_abbrev})
|
||||
endif()
|
||||
else()
|
||||
# Valid git checkout, use accurate information.
|
||||
set(YOSYS_CHECKOUT_INFO ${git_abbrev})
|
||||
if (git_dirty)
|
||||
string(APPEND YOSYS_CHECKOUT_INFO "-dirty")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT YOSYS_ORIGIN_INFO)
|
||||
# Build YOSYS_ORIGIN_INFO (git repository origin and branch)
|
||||
if (git_origin AND git_branch)
|
||||
string(REGEX REPLACE "^https://|.git$" "" git_origin ${git_origin})
|
||||
if (git_origin STREQUAL "github.com/YosysHQ/yosys" AND git_branch MATCHES "^HEAD|main|release/v.+$")
|
||||
# Nothing to highlight.
|
||||
set(YOSYS_ORIGIN_INFO "")
|
||||
else()
|
||||
# Highlight clone URL and branch.
|
||||
set(YOSYS_ORIGIN_INFO "${git_origin} at ${git_branch}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (YOSYS_ORIGIN_INFO)
|
||||
message(STATUS "Git commit ${YOSYS_CHECKOUT_INFO} from ${YOSYS_ORIGIN_INFO}")
|
||||
else()
|
||||
message(STATUS "Git commit ${YOSYS_CHECKOUT_INFO}")
|
||||
endif()
|
||||
|
||||
return(PROPAGATE
|
||||
YOSYS_VERSION_MAJOR
|
||||
YOSYS_VERSION_MINOR
|
||||
YOSYS_VERSION_COMMIT
|
||||
YOSYS_VERSION
|
||||
YOSYS_CHECKOUT_INFO
|
||||
YOSYS_ORIGIN_INFO
|
||||
)
|
||||
endfunction()
|
||||
|
||||
# Syntax:
|
||||
#
|
||||
# yosys_version_file(<input> <output>)
|
||||
#
|
||||
# Templates `<output>` file based on `<input>` with the following substitutions:
|
||||
# - `@YOSYS_VERSION@`: version in `<major>.<minor>+<post>` format
|
||||
# - `@YOSYS_BUILD_INFO@`: free-form build information
|
||||
# (not actually entirely free-form as external software tries to parse it sometimes)
|
||||
#
|
||||
# Must have executed `yosys_extract_version()` first.
|
||||
#
|
||||
function(yosys_version_file arg_INPUT arg_OUTPUT)
|
||||
set(YOSYS_BUILD_INFO "Yosys")
|
||||
string(APPEND YOSYS_BUILD_INFO " ${YOSYS_VERSION}")
|
||||
string(APPEND YOSYS_BUILD_INFO " (git sha1 ${YOSYS_CHECKOUT_INFO},")
|
||||
if (CMAKE_BUILD_TYPE)
|
||||
string(APPEND YOSYS_BUILD_INFO " ${CMAKE_BUILD_TYPE},")
|
||||
endif()
|
||||
string(APPEND YOSYS_BUILD_INFO " ${CMAKE_CXX_COMPILER_ID}")
|
||||
string(APPEND YOSYS_BUILD_INFO " ${CMAKE_CXX_COMPILER}")
|
||||
string(APPEND YOSYS_BUILD_INFO " ${CMAKE_CXX_COMPILER_VERSION})")
|
||||
if (YOSYS_ORIGIN_INFO)
|
||||
string(APPEND YOSYS_BUILD_INFO " [${YOSYS_ORIGIN_INFO}]")
|
||||
endif()
|
||||
|
||||
configure_file(${arg_INPUT} ${arg_OUTPUT} @ONLY)
|
||||
endfunction()
|
||||
2
cmake/YosysVersionData.cmake
Normal file
2
cmake/YosysVersionData.cmake
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
set(YOSYS_VERSION_MAJOR 0)
|
||||
set(YOSYS_VERSION_MINOR 64)
|
||||
8
cmake/toolchain/toolchain-mingw-i686.cmake
Normal file
8
cmake/toolchain/toolchain-mingw-i686.cmake
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
|
||||
set(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
|
||||
set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
8
cmake/toolchain/toolchain-mingw-x86_64.cmake
Normal file
8
cmake/toolchain/toolchain-mingw-x86_64.cmake
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
|
||||
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
|
||||
set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
Loading…
Add table
Add a link
Reference in a new issue