Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,26 @@ concore stop

For detailed CLI documentation, see [concore_cli/README.md](concore_cli/README.md).

## Configuration

_concore_ supports customization through configuration files in the `CONCOREPATH` directory (defaults to the _concore_ installation directory):

- **concore.tools** - Override tool paths (one per line, `KEY=value` format):
```
CPPEXE=/usr/local/bin/g++-12
PYTHONEXE=/usr/bin/python3.11
VEXE=/opt/iverilog/bin/iverilog
OCTAVEEXE=/snap/bin/octave
```
Supported keys: `CPPWIN`, `CPPEXE`, `VWIN`, `VEXE`, `PYTHONEXE`, `PYTHONWIN`, `MATLABEXE`, `MATLABWIN`, `OCTAVEEXE`, `OCTAVEWIN`

- **concore.octave** - Treat `.m` files as Octave instead of MATLAB (presence = enabled)
- **concore.mcr** - MATLAB Compiler Runtime path (single line)
- **concore.sudo** - Docker command override (e.g., `docker` instead of `sudo docker`)
- **concore.repo** - Docker repository override

Tool paths can also be set via environment variables (e.g., `CONCORE_CPPEXE=/usr/bin/g++`). Priority: config file > env var > defaults.

For a detailed and more scientific documentation, please read our extensive [open-access research paper on CONTROL-CORE](https://doi.org/10.1109/ACCESS.2022.3161471). This paper has a complete discussion on the CONTROL-CORE architecture and deployment, together with the commands to execute the studies in different programming languages and programming environments (Ubuntu, Windows, MacOS, Docker, and distributed execution).


Expand Down
45 changes: 35 additions & 10 deletions mkconcore.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,19 @@ def safe_name(value, context, allow_path=False):

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))

def _load_tool_config(filepath):
tools = {}
with open(filepath, "r") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
k, v = line.split("=", 1)
k, v = k.strip(), v.strip()
if v:
tools[k] = v
return tools

def _resolve_concore_path():
script_concore = os.path.join(SCRIPT_DIR, "concore.py")
if os.path.exists(script_concore):
Expand All @@ -109,16 +122,16 @@ def _resolve_concore_path():
GRAPHML_FILE = sys.argv[1]
TRIMMED_LOGS = True
CONCOREPATH = _resolve_concore_path()
CPPWIN = "g++" #Windows C++ 6/22/21
CPPEXE = "g++" #Ubuntu/macOS C++ 6/22/21
VWIN = "iverilog" #Windows verilog 6/25/21
VEXE = "iverilog" #Ubuntu/macOS verilog 6/25/21
PYTHONEXE = "python3" #Ubuntu/macOS python3
PYTHONWIN = "python" #Windows python3
MATLABEXE = "matlab" #Ubuntu/macOS matlab
MATLABWIN = "matlab" #Windows matlab
OCTAVEEXE = "octave" #Ubuntu/macOS octave
OCTAVEWIN = "octave" #Windows octave
CPPWIN = os.environ.get("CONCORE_CPPWIN", "g++") #Windows C++ 6/22/21
CPPEXE = os.environ.get("CONCORE_CPPEXE", "g++") #Ubuntu/macOS C++ 6/22/21
VWIN = os.environ.get("CONCORE_VWIN", "iverilog") #Windows verilog 6/25/21
VEXE = os.environ.get("CONCORE_VEXE", "iverilog") #Ubuntu/macOS verilog 6/25/21
PYTHONEXE = os.environ.get("CONCORE_PYTHONEXE", "python3") #Ubuntu/macOS python3
PYTHONWIN = os.environ.get("CONCORE_PYTHONWIN", "python") #Windows python3
MATLABEXE = os.environ.get("CONCORE_MATLABEXE", "matlab") #Ubuntu/macOS matlab
MATLABWIN = os.environ.get("CONCORE_MATLABWIN", "matlab") #Windows matlab
OCTAVEEXE = os.environ.get("CONCORE_OCTAVEEXE", "octave") #Ubuntu/macOS octave
OCTAVEWIN = os.environ.get("CONCORE_OCTAVEWIN", "octave") #Windows octave
M_IS_OCTAVE = False #treat .m as octave
MCRPATH = "~/MATLAB/R2021a" #path to local Ubunta Matlab Compiler Runtime
DOCKEREXE = "sudo docker"#assume simple docker install
Expand Down Expand Up @@ -147,6 +160,18 @@ def _resolve_concore_path():
with open(CONCOREPATH+"/concore.repo", "r") as f:
DOCKEREPO = f.readline().strip() #docker id for repo

if os.path.exists(CONCOREPATH+"/concore.tools"):
_tools = _load_tool_config(CONCOREPATH+"/concore.tools")
CPPWIN = _tools.get("CPPWIN", CPPWIN)
CPPEXE = _tools.get("CPPEXE", CPPEXE)
VWIN = _tools.get("VWIN", VWIN)
VEXE = _tools.get("VEXE", VEXE)
PYTHONEXE = _tools.get("PYTHONEXE", PYTHONEXE)
PYTHONWIN = _tools.get("PYTHONWIN", PYTHONWIN)
MATLABEXE = _tools.get("MATLABEXE", MATLABEXE)
MATLABWIN = _tools.get("MATLABWIN", MATLABWIN)
OCTAVEEXE = _tools.get("OCTAVEEXE", OCTAVEEXE)
OCTAVEWIN = _tools.get("OCTAVEWIN", OCTAVEWIN)

prefixedgenode = ""
sourcedir = sys.argv[2]
Expand Down
76 changes: 76 additions & 0 deletions tests/test_tool_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import pytest
import os

# can't import mkconcore directly (sys.argv at module level), so we duplicate the parser
def _load_tool_config(filepath):
tools = {}
with open(filepath, "r") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
k, v = line.split("=", 1)
k, v = k.strip(), v.strip()
if v:
tools[k] = v
return tools


class TestLoadToolConfig:

def test_basic_overrides(self, temp_dir):
cfg = os.path.join(temp_dir, "concore.tools")
with open(cfg, "w") as f:
f.write("CPPEXE=/usr/local/bin/g++-12\n")
f.write("PYTHONEXE=/usr/bin/python3.11\n")

tools = _load_tool_config(cfg)
assert tools["CPPEXE"] == "/usr/local/bin/g++-12"
assert tools["PYTHONEXE"] == "/usr/bin/python3.11"
assert "VEXE" not in tools

def test_comments_and_blanks_ignored(self, temp_dir):
cfg = os.path.join(temp_dir, "concore.tools")
with open(cfg, "w") as f:
f.write("# custom tool paths\n")
f.write("\n")
f.write("OCTAVEEXE = /snap/bin/octave\n")
f.write("# MATLABEXE = /opt/matlab/bin/matlab\n")

tools = _load_tool_config(cfg)
assert tools["OCTAVEEXE"] == "/snap/bin/octave"
assert "MATLABEXE" not in tools

def test_empty_value_skipped(self, temp_dir):
cfg = os.path.join(temp_dir, "concore.tools")
with open(cfg, "w") as f:
f.write("CPPWIN=\n")
f.write("VEXE = \n")

tools = _load_tool_config(cfg)
assert "CPPWIN" not in tools
assert "VEXE" not in tools

def test_value_with_equals_sign(self, temp_dir):
cfg = os.path.join(temp_dir, "concore.tools")
with open(cfg, "w") as f:
f.write("CPPEXE=C:\\Program Files\\g++=fast\n")

tools = _load_tool_config(cfg)
assert tools["CPPEXE"] == "C:\\Program Files\\g++=fast"

def test_whitespace_around_key_value(self, temp_dir):
cfg = os.path.join(temp_dir, "concore.tools")
with open(cfg, "w") as f:
f.write(" VWIN = C:\\iverilog\\bin\\iverilog.exe \n")

tools = _load_tool_config(cfg)
assert tools["VWIN"] == "C:\\iverilog\\bin\\iverilog.exe"

def test_empty_file(self, temp_dir):
cfg = os.path.join(temp_dir, "concore.tools")
with open(cfg, "w") as f:
pass

tools = _load_tool_config(cfg)
assert tools == {}