How to write a makefile where the compiled object files are in a different directory with a different name?

孤街浪徒 提交于 2019-12-07 23:21:18

问题


So I'm trying to write a Makefile to use with QuestaSim and systemverilog files. If you don't know what that is (and most people won't) then don't worry, it's not that relevant to my problem.

I have a project director containing: src/ work/ Makefile

the src/ directory contains several directories which each contain source files.

the work/ directory doesn't initially exist, and is created by the makefile.

when I call my "compiler" which is called vlog, on a .sv file a directory gets created in the work folder with the same name as the .sv file without the suffix. In that directory are three files the one that I'll use as my "object' file is _primary.dat.

So for example, calling "vlog src/interface/my_interface.sv" creates (if it succeeds) work/my_interface/_primary.dat

My .sv files also need to be compiled in a specific order, and I only want to compile them if the source file or one of their dependencies has changed.

I can turn the path to the .sv file into the path to the relevant _primary.dat file using "$(addsuffix /_primary.dat, $(addprefix $(VLIB_DIR)/, $(basename $(notdir $(SRC)))))" however the reverse is impossible, as we loose the directory structure.

So I think what I want is some sort of map from object -> src. So that in my $(OBJ): target, I can do "vlog $(getsrc $@)".

After that I have to deal with the compile order and dependencies, but I can probably work that out.

Any suggestions?


回答1:


I found a solution that works. I'm not sure it's the neatest, but I'll post it here to help anyone else who has this problem.

Basically I create a macro that takes two arguments: the .sv source file path and name, and a list of dependencies. This turns the source file path into the object file path and creates that as a target. With a dependency on the source file and any passed in dependencies. I then create a variable containing a list of all my sources. Finally I do: $(foreach src,$(SRCS),$(eval $(call create_target_for, $(src)))) which creates all my targets.

Additionally I have each subdirectory as a phony target, with the relevant dependencies, allowing me to get the correct compile order on directories.

The only thing missing is if I need to ensure files in a single directory have the correct compile order.

My Makefile:

# Makefile for use in building all my UVM components
# ----------------------------------------------------------------------------------
# Requirements:
#   QuestaSim - We use the vlog compiler packaged with QuestaSim.
#     ModelSim also comes with vlog, but doesn't really support UVM.
#   UVM_INCLUDE_DIR environment var - This should point to the UVM src directory.
#     For me this is: C:\questasim_10.0b\verilog_src\uvm-1.0p1\src
# ----------------------------------------------------------------------------------
# Notes:
#   The vlog compiler creates an output folder in the VLIB_DIR directors
#   per package/module/interface with the same name as the entity
#   Any capitals are replace with @ followed by the lower case letter
#   IE. FooBar -> @foo@bar
#   This makefile requires that:
#     All interfaces end in _if
#     All packages end in _pkg
#     Each file can only contain a single interface, package or module
#     No capitals in package/module/interface naems
#     The package/module/interface has the same name as the file

# some variabls to use later
VLIB_DIR    = ./work
VLOG_FLAGS  = +incdir+$(UVM_INCLUDE_DIR)

# src files - per directory for use with compile orders
#             ie. transactions have to be compiled before drivers
INTERFACE_SRCS      = $(wildcard src/interfaces/*.sv)
CONFIG_SRCS         = $(wildcard src/configs/*.sv)
TRANSACTION_SRCS    = $(wildcard src/transactions/*.sv)
SEQUENCE_SRCS       = $(wildcard src/sequences/*.sv)
DRIVER_SRCS         = $(wildcard src/drivers/*.sv)
MONITOR_SRCS        = $(wildcard src/monitors/*.sv)
AGENT_SRCS          = $(wildcard src/agents/*.sv)
SCOREBOARD_SRCS     = $(wildcard src/scoreboards/*.sv)

# all source files - for use with creating makefile targets
SRCS                = $(INTERFACE_SRCS) \
                      $(CONFIG_SRCS) \
                      $(TRANSACTION_SRCS) \
                      $(SEQUENCE_SRCS) \
                      $(DRIVER_SRCS) \
                      $(MONITOR_SRCS) \
                      $(AGENT_SRCS) \
                      $(SCOREBOARD_SRCS)

# list of all the components
COMPONENTS  = interfaces \
              configs \
              transactions \
              sequences \
              drivers \
              monitors \
              agents \
              scoreboards

# colours for use in echo commands for highlighting
COLOUR_NONE     = \x1b[0m
COLOUR_RED      = \x1b[31;01m
COLOUR_BLUE     = \x1b[34;01m
COLOUR_GREEN    = \x1b[32;01m

# macros to turn a .sv file into the compiled file in the relevant VLIB_DIR subdirectory
# src/abc/def.sv -> $(VLIB_DIR)/def/_primary.dat
src2obj     = $(addsuffix /_primary.dat, $(addprefix $(VLIB_DIR)/, $(basename $(notdir $(1)))))

# macro to create a target for a given source file
# it takes two arguments:
# 1) the path and name of the source file
# 2) any dependencies
# It then creates a traget on the relevant _primary.dat (questaSim created object)
# with a dependency on the source file, and any other passed in dependencies
define create_target_for

$$(info $COLOUR_GREEN create_target_for called on $(1))
$$(info creating target $(call src2obj, $(1)))
$$(info with dependencies $(VLIB_DIR) $(1) $(2))
$$(info )
$(call src2obj, $(1)): $(1) $(2)
    @echo -e "$(COLOUR_BLUE)compiling $(1) because of changes in: $$? $(COLOUR_NONE)\n"
    vlog $(VLOG_FLAGS) $(1)

endef

# default rule is to create the library, compile the UVM pkg and all the components
all: $(VLIB_DIR) UVM $(COMPONENTS)

# create the questaSim library if it's not already there
$(VLIB_DIR):
    vlib $(VLIB_DIR)
    @echo -e "$(COLOUR_GREEN)Created the $(VLIB_DIR) library$(COLOUR_NONE)\n"

# compile the UVM library
$(VLIB_DIR)/uvm_pkg/_primary.dat:
    vlog +incdir+$(UVM_INCLUDE_DIR) $(UVM_INCLUDE_DIR)/uvm.sv
    @echo -e "$(COLOUR_GREEN)Compiled the UVM package$(COLOUR_NONE)\n"

# simple alias
UVM: $(VLIB_DIR) $(VLIB_DIR)/uvm_pkg/_primary.dat

# create targets for all our sources
# note with this method we can't set dependencies within a single directory
$(foreach src,$(SRCS),$(eval $(call create_target_for, $(src))))

# define a phony target per directory so we can specify compile order
interfaces: $(VLIB_DIR) UVM \
            $(call src2obj, $(INTERFACE_SRCS))
    @echo -e "$(COLOUR_GREEN)Compiled all $@$(COLOUR_NONE)\n"

configs: $(VLIB_DIR) UVM \
         $(call src2obj, $(CONFIG_SRCS))
    @echo -e "$(COLOUR_GREEN)Compiled all $@$(COLOUR_NONE)\n"

transactions: $(VLIB_DIR) UVM \
              $(call src2obj, $(TRANSACTION_SRCS))
    @echo -e "$(COLOUR_GREEN)Compiled all $@$(COLOUR_NONE)\n"

sequences: $(VLIB_DIR) UVM \
           transactions \
           $(call src2obj, $(SEQUENCE_SRCS))
    @echo -e "$(COLOUR_GREEN)Compiled all $@$(COLOUR_NONE)\n"

drivers: $(VLIB_DIR) UVM \
         transactions interfaces \
         $(call src2obj, $(DRIVER_SRCS))
    @echo -e "$(COLOUR_GREEN)Compiled all $@$(COLOUR_NONE)\n"

monitors: $(VLIB_DIR) UVM \
          transactions interfaces \
          $(call src2obj, $(MONITOR_SRCS))
    @echo -e "$(COLOUR_GREEN)Compiled all $@$(COLOUR_NONE)\n"

agents: $(VLIB_DIR) UVM \
        drivers monitors transactions configs interfaces \
        $(call src2obj, $(AGENT_SRCS))
    @echo -e "$(COLOUR_GREEN)Compiled all $@$(COLOUR_NONE)\n"

scoreboards: $(call src2obj, $(SCOREBOARD_SRCS))
    @echo -e "$(COLOUR_GREEN)Compiled all $@$(COLOUR_NONE)\n"

# delete the library and all compiled files
clean:
    if [ -d $(VLIB_DIR) ]; then vdel -lib $(VLIB_DIR) -all; fi;

.PHONY: clean UVM $(COMPONENTS)


来源:https://stackoverflow.com/questions/38512489/how-to-write-a-makefile-where-the-compiled-object-files-are-in-a-different-direc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!