You have two possibilities a) your own build script or b) just use truffle framework. The first option is strait forward but has some drawbacks. When you start with writing contracts it is a good idea to understand the way the sol compiler works, but later the truffle framework helps you to manage more complex scenarios (i.e. like migrations, testing, deployment and validation requests to etherscan).
To answer your question (building several contracts with a single script):
This code is an early script of a project I did last year. In this code you compile a main contract called CertificateManagement.sol and some dependency from the OpenZeppelin libraries for role management as well as the Migrations.sol code.
// Dependencies
const solc = require("solc");
const fs = require("fs");
// Parameter default values
let BUILD_TARGET_PATH = './build/';
let contractBuild = async () => {
// Creates target path in the case it doesn't exists
fs.mkdir(BUILD_TARGET_PATH, {recursive: true}, (err) => {
if (err) throw err;
// loading the source code from a solidity file
let input = {
language: 'Solidity',
sources: {
//
// CertificateManagement.sol
'CertificateManagement.sol': {
content: fs.readFileSync('contracts/CertificateManagement.sol', 'utf8'),
},
//
// Pausable.sol
'openzeppelin/lifecycle/Pausable.sol': {
content: fs.readFileSync('contracts/openzeppelin/lifecycle/Pausable.sol', 'utf8'),
},
'./openzeppelin/lifecycle/Pausable.sol': {
content: fs.readFileSync('contracts/openzeppelin/lifecycle/Pausable.sol', 'utf8'),
},
//
// PauserRole.sol
'./openzeppelin/access/roles/PauserRole.sol': {
content: fs.readFileSync('contracts/openzeppelin/access/roles/PauserRole.sol', 'utf8'),
},
'../access/roles/PauserRole.sol': {
content: fs.readFileSync('contracts/openzeppelin/access/roles/PauserRole.sol', 'utf8'),
},
'openzeppelin/access/roles/PauserRole.sol': {
content: fs.readFileSync('contracts/openzeppelin/access/roles/PauserRole.sol', 'utf8'),
},
//
// Roles.sol
'Roles.sol': {
content: fs.readFileSync('contracts/openzeppelin/access/Roles.sol', 'utf8'),
},
'../Roles.sol': {
content: fs.readFileSync('contracts/openzeppelin/access/Roles.sol', 'utf8'),
},
'../access/Roles.sol': {
content: fs.readFileSync('contracts/openzeppelin/access/Roles.sol', 'utf8'),
},
'./openzeppelin/access/Roles.sol': {
content: fs.readFileSync('contracts/openzeppelin/access/Roles.sol', 'utf8'),
},
'openzeppelin/access/Roles.sol': {
content: fs.readFileSync('contracts/openzeppelin/access/Roles.sol', 'utf8'),
},
//
// WhitelistedRole.sol
'openzeppelin/access/roles/WhitelistedRole.sol': {
content: fs.readFileSync('contracts/openzeppelin/access/roles/WhitelistedRole.sol', 'utf8'),
},
//
// WhitelistAdminRole.sol
'WhitelistAdminRole.sol': {
content: fs.readFileSync('contracts/openzeppelin/access/roles/WhitelistAdminRole.sol', 'utf8'),
},
'./WhitelistAdminRole.sol': {
content: fs.readFileSync('contracts/openzeppelin/access/roles/WhitelistAdminRole.sol', 'utf8'),
},
'openzeppelin/access/roles/WhitelistAdminRole.sol': {
content: fs.readFileSync('contracts/openzeppelin/access/roles/WhitelistAdminRole.sol', 'utf8'),
},
//
// WhitelistedRole.sol
'WhitelistedRole.sol': {
content: fs.readFileSync('contracts/openzeppelin/access/roles/WhitelistedRole.sol', 'utf8'),
},
//
// Migrations.sol
'Migrations.sol': {
content: fs.readFileSync('contracts/Migrations.sol', 'utf8'),
},
},
settings: {
outputSelection: {'*': {'*': ['*']}}
}
};
// compile the solidity code
let compiled = solc.compile(JSON.stringify(input));
console.log("Compiling -> OK" );
let output = JSON.parse(compiled);
for (let contractJson in output.contracts) {
if (contractJson.startsWith("CertificateManagement.")) {
fs.writeFile(BUILD_TARGET_PATH + '/' + contractJson.replace(".sol", ".json"), JSON.stringify(output.contracts[contractJson][contractJson.replace(".sol", "")]), function (err) {
console.log("\nJSON saved -> OK\n "+ BUILD_TARGET_PATH + contractJson.replace(".sol", ".json"));
if (err) throw err;
});
}
}
// Save bytecode
let bytecode = '0x' + output.contracts['CertificateManagement.sol']['CertificateManagement'].evm.bytecode.object;
console.log('\nByte Code -> OK');
fs.writeFile(BUILD_TARGET_PATH + 'CertificateManagement.bytecode', bytecode, function (err) {
console.log("\nCode saved -> OK\n "+ BUILD_TARGET_PATH + "CertificateManagement.bytecode");
if (err) throw err;
});
// Logging of methods
console.log('\nIndentifiers -> OK\n');
let methodIdentifiers = output.contracts['CertificateManagement.sol']['CertificateManagement'].evm.methodIdentifiers;
for (let indentifier in methodIdentifiers) {
console.log(" " + indentifier);
}
// save public interface of contract
let abi = output.contracts['CertificateManagement.sol']['CertificateManagement'].abi;
fs.writeFile(BUILD_TARGET_PATH + 'CertificateManagement.abi', JSON.stringify(abi), function (err) {
console.log("\nABI saved -> OK\n "+ BUILD_TARGET_PATH + "CertificateManagement.abi");
console.log(" ");
if (err) throw err;
});
});
};
contractBuild();