__main__.py 13.3 KB
Newer Older
1
#!/usr/bin/python
2
# -*- coding: utf-8 -*-
3
#
4
# Copyright (c) 2013 - 2015 CERN
Pawel Szostek's avatar
Pawel Szostek committed
5
# Author: Pawel Szostek (pawel.szostek@cern.ch)
6
# Multi-tool support by Javier D. Garcia-Lasheras (javier@garcialasheras.com)
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
#
# This file is part of Hdlmake.
#
# Hdlmake is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Hdlmake is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Hdlmake.  If not, see <http://www.gnu.org/licenses/>.

23

Pawel Szostek's avatar
Pawel Szostek committed
24
from __future__ import print_function
25
import os
26
import importlib
27
import argparse
28
import logging
Pawel Szostek's avatar
Pawel Szostek committed
29
import sys
30 31 32 33 34 35 36 37

from . import global_mod
from .util.termcolor import colored
from .manifest_parser import ManifestParser
from .module_pool import ModulePool
from .env import Env
from . import fetch as fetch_mod
from .action import (CheckCondition, CleanModules, FetchModules, GenerateFetchMakefile, ListFiles,
38 39
                    ListModules, MergeCores, GenerateSimulationMakefile,
                    GenerateSynthesisMakefile, GenerateRemoteSynthesisMakefile, GenerateSynthesisProject)
40
from ._version import __version__
41

42
#from argument_parser import get_argument_parser
43 44 45 46 47

#try:
#    from build_hash import BUILD_ID
#except:
#    BUILD_ID = "unrecognized"
48 49


50
def main():
51
    """This is the main function, where HDLMake starts.
52 53 54 55
    Here, we make the next processes:
        -- parse command
        -- check and set the environment
        -- prepare the global module containing the heavy common stuff
56
    """
57

58 59
    # Remember current path
    global_mod.current_path = os.getcwd()
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

    #
    # SET & GET PARSER
    #
    parser = _get_parser()

    #
    # PARSE & GET OPTIONS
    #
    options = _get_options(sys, parser)
    global_mod.options = options


    # global_mod_assigned!!!
    env = Env(options)
    global_mod.env = env


    numeric_level = getattr(logging, options.log.upper(), None)
    if not isinstance(numeric_level, int):
        sys.exit('Invalid log level: %s' % options.log)

    logging.basicConfig(format=colored("%(levelname)s", "yellow") + colored("\t%(filename)s:%(lineno)d: %(funcName)s()\t", "blue") + "%(message)s", level=numeric_level)
    logging.debug(str(options))

    modules_pool = ModulePool()
    modules_pool.new_module(parent=None,
87
                            url=global_mod.current_path,
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
                            source=fetch_mod.LOCAL,
                            fetchto=".",
                            process_manifest=False)

    # Setting top_module as top module of design (ModulePool class)
    if modules_pool.get_top_module().manifest is None:
        logging.info("No manifest found. At least an empty one is needed")
        logging.info("To see some help, type hdlmake --help")
        sys.exit("Exiting")

    # Setting global variable (global_mod.py)
    top_mod = modules_pool.get_top_module()
    global_mod.top_module = top_mod

    #global_mod.global_target = global_mod.top_module.target
    global_mod.mod_pool = modules_pool

    modules_pool.process_top_module_manifest()

    #
    # Load global tool object (global_mod.py)
    #
110 111 112 113
    if not top_mod.action:
        logging.error("`action' manifest variable has to be specified. "
                      "Otherwise hdlmake doesn't know how to handle the project")
        quit()
114
    if top_mod.action == "synthesis":
115 116 117 118
        if not top_mod.syn_tool:
            logging.error("`syn_tool' manifest variable has to be specified. "
                          "Otherwise hdlmake doesn't know how to synthesize the project")
            quit()
119 120
        tool_name = top_mod.syn_tool
    elif top_mod.action == "simulation":
121 122 123 124
        if not top_mod.sim_tool:
            logging.error("`sim_tool' manifest variable has to be specified. "
                          "Otherwise hdlmake doesn't know how to simulate the project")
            quit()
125 126 127
        tool_name = top_mod.sim_tool
    logging.info('import tool module: ' + tool_name)
    try:
128
        tool_module = importlib.import_module("hdlmake.tools.%s.%s" % (tool_name, tool_name))
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
    except Exception as e:
        logging.error(e)
        quit()

    global_mod.tool_module = tool_module


    #env.top_module = modules_pool.get_top_module()
    env.check_env(verbose=False)
    #env.check_env_wrt_manifest(verbose=False)


    #                                   #
    # EXECUTE THE COMMANDS/ACTIONS HERE #
    #                                   #


    if options.command == "check-env":
        env.check_env(verbose=True)
        quit()

    if options.command == "check-manifest":
        env.check_manifest(modules_pool.get_top_module().manifest, verbose=True)
        quit()

    if options.command == "manifest-help":
        ManifestParser().print_help()
        quit()

    if options.command == "auto":
        logging.info("Running automatic flow.")
        if not top_mod.action:
            logging.error("`action' manifest variable has to be specified. "
                          "Otherwise hdlmake doesn't know how to handle the project")
            quit()
        if top_mod.action == "simulation":
            if not top_mod.sim_tool:
                logging.error("`sim_tool' manifest variable has to be specified. "
                              "Otherwise hdlmake doesn't know how to simulate the project")
                quit()
169
            action = [ GenerateSimulationMakefile ]
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
        elif top_mod.action == "synthesis":
            if not top_mod.syn_tool:
                logging.error("`syn_tool' manifest variable has to be specified. "
                              "Otherwise hdlmake doesn't know how to synthesize the project")
                quit()
            action = [
                GenerateSynthesisProject,
                GenerateSynthesisMakefile,
                GenerateRemoteSynthesisMakefile
            ]
            
            # TODO: I advocate for removing the remote options -- too much pain, too little gain!!
            # Why shouldn't we directly use ssh, screen, scp and rsync on a remote HDLMake deployment??

    #elif options.command == "make-simulation":
    #    action = [ GenerateSimulationMakefile ]
    #elif options.command == "make-fetch":
    #    action = [ GenerateFetchMakefile ]
    #elif options.command == "make-ise":
    #    action = [ GenerateSynthesisMakefile ]
    #elif options.command == "make-remote":
    #    action = [ GenerateRemoteSynthesisMakefile ]
    elif options.command == "fetch":
        action = [ FetchModules ]
    elif options.command == "clean":
        action = [ CleanModules ]
    elif options.command == "list-mods":
        action = [ ListModules ]
    elif options.command == "list-files":
        action = [ ListFiles ]
    elif options.command == "merge-cores":
        action = [ MergeCores ]
    elif options.command == "ise-project":
        action = [ GenerateSynthesisProject ]
    elif options.command == "quartus-project":
        action = [ GenerateSynthesisProject ]
    elif options.command == "project":
        action = [ GenerateSynthesisProject ]

    try:
        for command in action:
            action_instance = command(modules_pool=modules_pool,
                                    options=options,
                                    env=env)
            action_instance.run()
    except Exception as e:
        import traceback
        logging.error(e)
        print("Trace:")
        traceback.print_exc()
220
        sys.exit("Exiting in failure because exception occurred")
221 222 223 224 225 226 227


def _get_parser():
    """This is the parser function, where options and commands are defined.
    Here, we make the next processes:
    """	

228
    usage = """hdlmake [command] [options]"""
229
    description = """Version %s\n
230
        To see optional arguments for particular command type:
Pawel Szostek's avatar
Pawel Szostek committed
231 232
        hdlmake <command> --help
\0
233
""" % (__version__,)
234

Pawel Szostek's avatar
Pawel Szostek committed
235 236 237
    parser = argparse.ArgumentParser("hdlmake",
                                     usage=usage,
                                     description=description)
Pawel Szostek's avatar
Pawel Szostek committed
238 239
    subparsers = parser.add_subparsers(title="commands", dest="command")

Pawel Szostek's avatar
Pawel Szostek committed
240 241 242 243 244
    check_env = subparsers.add_parser("check-env",
                                      help="check environment for HDLMAKE-related settings",
                                      description="Look for environmental variables specific for HDLMAKE.\n"
                                                  "Hdlmake will examine presence of supported synthesis and simulation"
                                                  "tools.\n")
245 246
    # check_manifest = subparsers.add_parser("check-manifest", help="check manifest for formal correctness")
    # check_manifest.add_argument("--top", help="indicate path to the top manifest", default=None)
Pawel Szostek's avatar
Pawel Szostek committed
247
    manifest_help = subparsers.add_parser("manifest-help", help="print manifest file variables description")
248

Pawel Szostek's avatar
Pawel Szostek committed
249
    fetch = subparsers.add_parser("fetch", help="fetch and/or update remote modules listed in Manifest")
250 251 252
    fetch.add_argument("--flatten", help="`flatten' modules' hierarchy by storing everything in top module's fetchto direactoru",
                       default=False, action="store_true")
    fetch.add_argument("--update", help="force updating of the fetched modules", default=False, action="store_true")
Pawel Szostek's avatar
Pawel Szostek committed
253
    clean = subparsers.add_parser("clean", help="remove all modules fetched for direct and indirect children of this module")
Pawel Szostek's avatar
Pawel Szostek committed
254
    listmod = subparsers.add_parser("list-mods", help="List all modules together with their files")
255
    listmod.add_argument("--with-files", help="list modules together with their files", default=False, action="store_true", dest="withfiles")
Pawel Szostek's avatar
Pawel Szostek committed
256 257 258 259
    listfiles = subparsers.add_parser("list-files", help="List all files in a form of a space-separated string")
    listfiles.add_argument("--delimiter", help="set delimitier for the list of files", dest="delimiter", default=' ')
    merge_cores = subparsers.add_parser("merge-cores", help="Merges entire synthesizable content of an project into a pair of VHDL/Verilog files")
    merge_cores.add_argument("--dest", help="name for output merged file", dest="dest", default=None)
260
    ise_proj = subparsers.add_parser("ise-project", help="create/update an ise project including list of project")
261 262
    ise_proj.add_argument("--generate-project-vhd", help="generate project.vhd file with a meta package describing the project",
                          dest="generate_project_vhd", default=False, action="store_true")
263
    quartus_proj = subparsers.add_parser("quartus-project", help="create/update a quartus project including list of project")
264
    synthesis_proj = subparsers.add_parser("project", help="create/update a project for the appropriated tool")
265 266 267 268 269

    condition_check = argparse.ArgumentParser()
    condition_check.add_argument("--tool", dest="tool", required=True)
    condition_check.add_argument("--reference", dest="reference", required=True)
    condition_check.add_argument("--condition", dest="condition", required=True)
270 271

    auto = subparsers.add_parser("auto", help="default action for hdlmake. Run when no args are given")
272
    auto.add_argument('-v', '--version', action='version', version=parser.prog + " " + __version__)
273 274 275 276
    auto.add_argument("--force", help="force hdlmake to generate the makefile, even if the specified tool is missing", default=False, action="store_true")
    auto.add_argument("--noprune", help="prevent hdlmake from pruning unneeded files", default=False, action="store_true")
    auto.add_argument("--generate-project-vhd", help="generate project.vhd file with a meta package describing the project",
                      dest="generate_project_vhd", default=False, action="store_true")
277

278
    parser.add_argument("--py", dest="arbitrary_code",
Pawel Szostek's avatar
Pawel Szostek committed
279
                        default="", help="add arbitrary code when evaluation all manifests")
280

281
    parser.add_argument("--log", dest="log",
Pawel Szostek's avatar
Pawel Szostek committed
282
                        default="info", help="set logging level (one of debug, info, warning, error, critical")
283 284 285
    parser.add_argument("--generate-project-vhd", help="generate project.vhd file with a meta package describing the project",
                          dest="generate_project_vhd", default=False, action="store_true")
    parser.add_argument("--force", help="force hdlmake to generate the makefile, even if the specified tool is missing", default=False, action="store_true")
286

287 288 289 290 291
    return parser



def _get_options(sys,parser):
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
    options = None
    if len(sys.argv[1:]) == 0:
            options = parser.parse_args(['auto'])

    elif len(sys.argv[1:]) == 1:
        if sys.argv[1] == "_conditioncheck":
            options = condition_check.parse_args(sys.argv[2:])
            env = Env(options)
            env.check_env()
            CheckCondition(modules_pool=None,
                           options=options,
                           env=env).run()
            quit()
        elif sys.argv[1] == "--help" or sys.argv[1] == "-h":
            options = parser.parse_args(sys.argv[1:])
Pawel Szostek's avatar
Pawel Szostek committed
307
        elif sys.argv[1].startswith('-'):
308
            options = parser.parse_args(["auto"]+sys.argv[1:])
Pawel Szostek's avatar
Pawel Szostek committed
309 310 311 312
        else:
            options = parser.parse_args(sys.argv[1:])
    else:
        options = parser.parse_args(sys.argv[1:])
313
    return options
314

315

316

317 318
if __name__ == "__main__":
    main()