f4pga: test pyF4PGA in CI

Signed-off-by: Unai Martinez-Corral <umartinezcorral@antmicro.com>
This commit is contained in:
Unai Martinez-Corral 2022-03-01 02:52:59 +01:00
parent 22003c2f49
commit 920d1d5ec3
22 changed files with 196 additions and 309 deletions

View File

@ -6,7 +6,8 @@ on:
jobs: jobs:
Run-tests:
Test-pip:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
@ -39,14 +40,20 @@ jobs:
- name: Test py4FPGA build - name: Test py4FPGA build
run: | run: |
cd f4pga-examples
export INSTALL_DIR=/opt/f4pga export INSTALL_DIR=/opt/f4pga
export PATH="$INSTALL_DIR/xc7/install/bin:$PATH"; export PATH="$INSTALL_DIR/xc7/install/bin:$PATH";
source "$INSTALL_DIR/xc7/conda/etc/profile.d/conda.sh" source "$INSTALL_DIR/xc7/conda/etc/profile.d/conda.sh"
conda activate xc7 conda activate xc7
pip install -r ../f4pga/requirements.txt cd f4pga
pip install --use-feature=in-tree-build .
cd ..
PYTHONPATH=$(pwd)/../f4pga python3 ../f4pga/sfbuild.py build --flow ../.github/sftest.json -t bitstream cd f4pga-examples
f4pga build --flow ../.github/sftest.json -t bitstream
- name: Test py4FPGA (PYTHONPATH)
run: |
PYTHONPATH=$(pwd) python3 f4pga/sfbuild.py
PYTHONPATH=$(pwd) python3 f4pga/sfbuild.py -h

View File

@ -1,146 +0,0 @@
# Installs sfbuild - experimental Symbiflow Build System
function(INSTALL_DIR)
# Create directory during installation phase
set(options)
set(one_value_args INSTALL_DIRECTORY)
set(multi_value_args)
cmake_parse_arguments(
INSTALL_DIR
"${options}"
"${one_value_args}"
"${multi_value_args}"
${ARGN}
)
set(make_dir_code "file(MAKE_DIRECTORY ${INSTALL_DIR_INSTALL_DIRECTORY})")
install(CODE ${make_dir_code})
endfunction()
function(INSTALL_DIR_CONTENT)
# Install files from ROOT_DIRECTORY/FILES_DIRECTORY directory into a FILES_DIRECTORY subdirectory of INSTALL_DIRECTORY
set(options)
set(one_value_args
ROOT_DIRECTORY
FILES_DIRECTORY
DESTINATION)
set(multi_value_args
FILES
INSTALL_OPTS)
cmake_parse_arguments(
INSTALL_DIR_CONTENT
"${options}"
"${one_value_args}"
"${multi_value_args}"
${ARGN}
)
if(NOT DEFINED INSTALL_DIR_CONTENT_ROOT_DIRECTORY)
set(INSTALL_DIR_CONTENT_ROOT_DIRECTORY .)
endif()
if(NOT DEFINED INSTALL_DIR_CONTENT_FILES_DIRECTORY)
set(INSTALL_DIR_CONTENT_FILES_DIRECTORY .)
endif()
set(file_paths)
foreach(file ${INSTALL_DIR_CONTENT_FILES})
list(APPEND file_paths ${INSTALL_DIR_CONTENT_ROOT_DIRECTORY}/${INSTALL_DIR_CONTENT_FILES_DIRECTORY}/${file})
endforeach()
install(FILES ${file_paths}
DESTINATION ${INSTALL_DIR_CONTENT_DESTINATION}/${INSTALL_DIR_CONTENT_FILES_DIRECTORY}
${INSTALL_DIR_CONTENT_INSTALL_OPTS})
endfunction()
find_package(Python3 COMPONENTS Interpreter REQUIRED)
get_target_property_required(VPR env VPR)
get_target_property_required(GENFASM env GENFASM)
set(SFBUILD_SUPPORTED_PLATFORMS
ql-eos-s3
xc7a50t
xc7a100t
xc7a200t
ql-k4n8_fast
ql-k4n8_slow)
# Create required directories
foreach(DIR_PATH ${SFBUILD_DIRECTORIES})
install_dir(INSTALL_DIRECTORY ${CMAKE_INSTALL_PREFIX}/bin/${DIR_PATH})
endforeach()
# Install sfbuild
install_dir_content(
FILES
__init__.py
sf_argparse.py
sf_cache.py
sf_flow_config.py
sf_module_inspector.py
sf_stage.py
sf_ugly.py
sfbuild.py
sfbuild
DESTINATION bin/sfbuild
INSTALL_OPTS
PERMISSIONS WORLD_EXECUTE WORLD_READ OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE)
install_dir_content(
FILES __init__.py
FILES_DIRECTORY sf_common
DESTINATION bin/sfbuild
INSTALL_OPTS
PERMISSIONS WORLD_EXECUTE WORLD_READ OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE)
install_dir_content(
FILES __init__.py
FILES_DIRECTORY sf_module
DESTINATION bin/sfbuild
INSTALL_OPTS
PERMISSIONS WORLD_EXECUTE WORLD_READ OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE)
install_dir_content(
FILES __init__.py
FILES_DIRECTORY sf_module_runner
DESTINATION bin/sfbuild
INSTALL_OPTS
PERMISSIONS WORLD_EXECUTE WORLD_READ OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE)
# Install common modules
install_dir_content(
FILES
fasm.py
generic_script_wrapper.py
io_rename.py
mkdirs.py
pack.py
place_constraints.py
place.py
route.py
synth.py
FILES_DIRECTORY sf_common_modules
DESTINATION bin/sfbuild
INSTALL_OPTS
PERMISSIONS WORLD_EXECUTE WORLD_READ OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE)
# Install platform flow definitions
set(sfbuild_supported_platform_defs)
foreach(SFBUILD_PLATFORM ${SFBUILD_SUPPORTED_PLATFORMS})
set(sfbuild_platform_def "${SFBUILD_PLATFORM}.json")
list(APPEND sfbuild_supported_platform_defs ${sfbuild_platform_def})
endforeach()
install_dir_content(
FILES ${sfbuild_supported_platform_defs}
FILES_DIRECTORY platforms
DESTINATION bin/sfbuild
INSTALL_OPTS
PERMISSIONS WORLD_EXECUTE WORLD_READ OWNER_WRITE OWNER_READ GROUP_READ)
# Install part_db
install_dir_content(
FILES
parts.json
FILES_DIRECTORY part_db
DESTINATION bin/sfbuild
INSTALL_OPTS
PERMISSIONS WORLD_READ OWNER_WRITE OWNER_READ GROUP_READ
)

View File

@ -1 +0,0 @@
import sfbuild

View File

@ -19,6 +19,7 @@
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
from pathlib import Path from pathlib import Path
from typing import List
from setuptools import setup as setuptools_setup from setuptools import setup as setuptools_setup
@ -27,6 +28,28 @@ F4PGA_FAM = environ.get('F4PGA_FAM', 'xc7')
packagePath = Path(__file__).resolve().parent packagePath = Path(__file__).resolve().parent
requirementsFile = packagePath / "requirements.txt"
# Read requirements file and add them to package dependency list
def get_requirements(file: Path) -> List[str]:
requirements = []
with file.open("r") as fh:
for line in fh.read().splitlines():
if line.startswith("#") or line == "":
continue
elif line.startswith("-r"):
# Remove the first word/argument (-r)
filename = " ".join(line.split(" ")[1:])
requirements += get_requirements(file.parent / filename)
elif line.startswith("https"):
# Convert 'URL#NAME' to 'NAME @ URL'
splitItems = line.split("#")
requirements.append("{} @ {}".format(splitItems[1], splitItems[0]))
else:
requirements.append(line)
return requirements
sf = "symbiflow" sf = "symbiflow"
shwrappers = "f4pga.wrappers.sh.__init__" shwrappers = "f4pga.wrappers.sh.__init__"
@ -54,15 +77,21 @@ setuptools_setup(
description="F4PGA.", description="F4PGA.",
url="https://github.com/chipsalliance/f4pga", url="https://github.com/chipsalliance/f4pga",
packages=[ packages=[
"f4pga",
"f4pga.sf_common_modules",
"f4pga.wrappers.sh", "f4pga.wrappers.sh",
], ],
package_dir={"f4pga": "."}, package_dir={"f4pga": "."},
package_data={ package_data={
'f4pga': ['platforms/*.json'],
'f4pga.wrappers.sh': ['xc7/*.f4pga.sh', 'quicklogic/*.f4pga.sh'] 'f4pga.wrappers.sh': ['xc7/*.f4pga.sh', 'quicklogic/*.f4pga.sh']
}, },
classifiers=[], classifiers=[],
python_requires='>=3.6', python_requires='>=3.6',
install_requires=list(set(get_requirements(requirementsFile))),
entry_points={ entry_points={
"console_scripts": wrapper_entrypoints "console_scripts": [
"f4pga = f4pga.sfbuild:main",
] + wrapper_entrypoints
}, },
) )

View File

@ -186,7 +186,7 @@ def fatal(code, message):
with a given return code. with a given return code.
""" """
print(f'[FATAL ERROR]: {message}') raise(Exception(f'[FATAL ERROR]: {message}'))
exit(code) exit(code)
class ResolutionEnv: class ResolutionEnv:

View File

@ -5,8 +5,8 @@
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #
import os import os
from sf_common import * from f4pga.sf_common import *
from sf_module import * from f4pga.sf_module import *
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #

View File

@ -49,8 +49,8 @@ import os
import shutil import shutil
import re import re
from sf_common import * from f4pga.sf_common import *
from sf_module import * from f4pga.sf_module import *
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #

View File

@ -27,9 +27,9 @@ Accepted module parameters:
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #
from sf_common import * from f4pga.sf_common import *
from sf_module import * from f4pga.sf_module import *
from sf_module_runner import get_module from f4pga.sf_module_runner import get_module
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #

View File

@ -12,8 +12,8 @@ lazily create the directories if they become necessary. """
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #
import os import os
from sf_common import * from f4pga.sf_common import *
from sf_module import * from f4pga.sf_module import *
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #

View File

@ -6,8 +6,8 @@
import os import os
import re import re
from sf_common import * from f4pga.sf_common import *
from sf_module import * from f4pga.sf_module import *
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #

View File

@ -5,8 +5,8 @@
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #
import os import os
from sf_common import * from f4pga.sf_common import *
from sf_module import * from f4pga.sf_module import *
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #

View File

@ -5,8 +5,8 @@
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #
import os import os
from sf_common import * from f4pga.sf_common import *
from sf_module import * from f4pga.sf_module import *
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #

View File

@ -6,8 +6,8 @@
import os import os
import shutil import shutil
from sf_common import * from f4pga.sf_common import *
from sf_module import * from f4pga.sf_module import *
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #

View File

@ -5,8 +5,8 @@
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #
import os import os
from sf_common import * from f4pga.sf_common import *
from sf_module import * from f4pga.sf_module import *
# ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- #

View File

@ -1,8 +1,8 @@
import os import os
import json import json
from sf_common import file_noext, ResolutionEnv, deep from f4pga.sf_common import file_noext, ResolutionEnv, deep
from sf_stage import Stage from f4pga.sf_stage import Stage
from copy import copy from copy import copy
_realpath_deep = deep(os.path.realpath) _realpath_deep = deep(os.path.realpath)

View File

@ -2,7 +2,7 @@
import abc import abc
from types import SimpleNamespace from types import SimpleNamespace
from sf_common import * from f4pga.sf_common import *
from colorama import Fore, Style from colorama import Fore, Style
class Module: class Module:

View File

@ -1,5 +1,5 @@
from sf_module import Module from f4pga.sf_module import Module
from sf_common import decompose_depname from f4pga.sf_common import decompose_depname
from colorama import Style from colorama import Style
def _get_if_qualifier(deplist: 'list[str]', qualifier: str): def _get_if_qualifier(deplist: 'list[str]', qualifier: str):

View File

@ -4,8 +4,8 @@ from contextlib import contextmanager
import importlib import importlib
import importlib.util import importlib.util
import os import os
from sf_module import Module, ModuleContext, get_mod_metadata from f4pga.sf_module import Module, ModuleContext, get_mod_metadata
from sf_common import ResolutionEnv, deep, sfprint from f4pga.sf_common import ResolutionEnv, deep, sfprint
from colorama import Fore, Style from colorama import Fore, Style
_realpath_deep = deep(os.path.realpath) _realpath_deep = deep(os.path.realpath)

View File

@ -1,6 +1,6 @@
from sf_common import decompose_depname, resolve_modstr from f4pga.sf_common import decompose_depname, resolve_modstr
from sf_module import Module from f4pga.sf_module import Module
from sf_module_runner import get_module, module_io from f4pga.sf_module_runner import get_module, module_io
class StageIO: class StageIO:
""" """

View File

@ -1,7 +1,7 @@
""" The "ugly" module is dedicated for some *ugly* workarounds """ """ The "ugly" module is dedicated for some *ugly* workarounds """
import os import os
import sf_common from f4pga.sf_common import sub as common_sub
def noisy_warnings(): def noisy_warnings():
""" Emit some noisy warnings """ """ Emit some noisy warnings """
@ -13,7 +13,7 @@ def generate_values():
""" Generate initial values, available in configs """ """ Generate initial values, available in configs """
return{ return{
'prjxray_db': sf_common.sub('prjxray-config').decode().replace('\n', ''), 'prjxray_db': common_sub('prjxray-config').decode().replace('\n', ''),
'python3': sf_common.sub('which', 'python3').decode().replace('\n', ''), 'python3': common_sub('which', 'python3').decode().replace('\n', ''),
'noisyWarnings': noisy_warnings() 'noisyWarnings': noisy_warnings()
} }

View File

@ -1,5 +0,0 @@
#!/bin/sh
MYDIR=`dirname $0`
python3 ${MYDIR}/sfbuild.py $@

View File

@ -21,30 +21,30 @@ that uses sfbuild. Iontains project-specific definitions needed within the flow,
such as list of source code files. such as list of source code files.
""" """
from pathlib import Path
from argparse import Namespace from argparse import Namespace
import os import os
from os import environ from os import environ
import json import json
from typing import Iterable from typing import Iterable
from colorama import Fore, Style from colorama import Fore, Style
from sf_common import ResolutionEnv, fatal, scan_modules, set_verbosity_level, \ from f4pga.sf_common import ResolutionEnv, fatal, scan_modules, set_verbosity_level, \
sfprint sfprint
from sf_module import * from f4pga.sf_module import *
from sf_cache import SymbiCache from f4pga.sf_cache import SymbiCache
import sf_ugly import f4pga.sf_ugly as sf_ugly
from sf_flow_config import ProjectFlowConfig, FlowConfig, FlowDefinition, \ from f4pga.sf_flow_config import ProjectFlowConfig, FlowConfig, FlowDefinition, \
open_project_flow_cfg, verify_platform_name, \ open_project_flow_cfg, verify_platform_name, \
verify_stage verify_stage
from sf_module_runner import * from f4pga.sf_module_runner import *
from sf_module_inspector import get_module_info from f4pga.sf_module_inspector import get_module_info
from sf_stage import Stage from f4pga.sf_stage import Stage
from sf_argparse import setup_argparser, get_cli_flow_config from f4pga.sf_argparse import setup_argparser, get_cli_flow_config
SYMBICACHEPATH = '.symbicache' SYMBICACHEPATH = '.symbicache'
mypath = os.path.realpath(os.sys.argv[0]) binpath = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(os.sys.argv[0])), '..'))
mypath = os.path.dirname(mypath) mypath = str(Path(__file__).resolve().parent)
binpath = os.path.realpath(os.path.join(mypath, '..'))
share_dir_path = os.path.realpath(f"{environ.get('INSTALL_DIR', '/usr/local')}/xc7/install/share/symbiflow") share_dir_path = os.path.realpath(f"{environ.get('INSTALL_DIR', '/usr/local')}/xc7/install/share/symbiflow")
@ -624,7 +624,7 @@ def cmd_show_dependencies(args: Namespace):
set_verbosity_level(-1) set_verbosity_level(-1)
if __name__ == '__main__': def main():
parser = setup_argparser() parser = setup_argparser()
args = parser.parse_args() args = parser.parse_args()
@ -640,3 +640,6 @@ if __name__ == '__main__':
sfprint(0, 'Please use a command.\nUse `--help` flag to learn more.') sfprint(0, 'Please use a command.\nUse `--help` flag to learn more.')
sfbuild_done() sfbuild_done()
if __name__ == '__main__':
main()