blob: 18e0b723d6057a089288fd3bce51908684bae956 [file] [log] [blame]
/* --COPYRIGHT--,EPL
* Copyright (c) 2008-2015 Texas Instruments Incorporated
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Texas Instruments - initial implementation
*
* --/COPYRIGHT--*/
/*
* ======== xe.c ========
* XDC host command tool
*
* This command runs command found along the package path.
*
* usage: xe [-n] cmd [arg ...]
*
* Options:
* -h - display this message
* -n - don't do build just echo build commands
*/
#include <xdc/std.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "host.h"
#include <xdc/services/host/lib/xutl.h>
#include <sys/stat.h>
#ifndef TISB_TREENAME
#define TISB_TREENAME "xdc-o17"
#endif
#define PNAME "/packages/xdc/bin"
#define PNAMELEN (sizeof(PNAME) - 1)
#define MAXNAME 512
#define MAXARG (2 * MAXNAME)
#define MAXARGS 128
#define MAXNEW 16
#if defined(xdc_target__os_Linux)
#include <unistd.h>
#define HOSTOS "HOSTOS=Linux"
#endif
#if defined(xdc_target__os_Windows)
#define HOSTOS "HOSTOS=Windows"
#define DIRSTR "\\"
#define PATHSTR ";"
#define MAKE "bin" DIRSTR "gmake.exe"
#include <windows.h> /* GetModuleFileName */
#include <io.h>
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#else /* Unix */
#define DIRSTR "/"
#define PATHSTR ":"
#define MAKE "bin" DIRSTR "gmake"
#endif
#define PACKPREFIX "PACKAGES="
#define PACKSUFFIX ""
#define XDCTOPMAKE (DIRSTR "packages" DIRSTR "xdc" DIRSTR "bld" DIRSTR "xdc_top.mak")
#define XDCMAKE (DIRSTR "packages" DIRSTR "xdc" DIRSTR "bld" DIRSTR "xdc.mak")
static Bool nflag = FALSE;
static Int verbose = 0;
static String xdcRoot; /* root path; i.e., $(XDCROOT) */
static Char rootDef[MAXARG]; /* XDCROOT=$(XDCROOT) */
static String xdcPathDef = NULL;/* XDCPATH= definition on command line */
static String packagePath; /* full expanded package path */
static String makeArgv[MAXARGS];
static Int makeArgc = 0;
static String progName;
static String usage = \
"usage: %s [-h] [-n] cmd [arg ...]\n" \
" -h - display this message and exit\n" \
" -n - show the make command but don't execute it\n";
static String optsUsage = \
" XDC_VERBOSE a number indicating 'degree' of verbosity; 0 => quiet\n";
static Void d2u(String buf);
static String findFile(String file, String path);
static char **genEnvp(String root, char *envp[]);
static String getPackagePath(String xdcPath);
static Bool isFile(String name);
static Void printSetEnv(String env);
static Void printVers(String progName);
/*
* ======== main ========
*/
int main(int argc, char *argv[], char *envp[])
{
Int status = 0;
Int i;
Int len;
String tmp, err;
progName = argv[0];
XUTL_init();
argv = XUTL_expandArgv(argc, argv, &argc, &err);
if (argv == NULL) {
fprintf(stderr, "%s: unable to expand command line arguments: %s\n",
progName, err);
exit(1);
}
if ((tmp = getenv("XDC_VERBOSE")) != NULL) {
verbose = atoi(tmp);
}
/* compute xdc root based on where this executable is installed */
xdcRoot = XUTL_getProgPath(progName);
d2u(xdcRoot);
len = strlen(xdcRoot);
tmp = xdcRoot + (len - PNAMELEN);
if (strcmp(tmp, PNAME) == 0) {
*tmp = '\0';
}
/* parse options */
for (i = 1; i < argc; i++) {
if (makeArgc >= MAXARGS) {
fprintf(stderr, "%s: out of memory.\n", progName);
exit(1);
}
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'n': {
nflag = TRUE;
break;
}
case 'h': {
fprintf(stderr, usage, progName);
fprintf(stderr, "\nEnvironment Variables\n");
fprintf(stderr, optsUsage);
exit(0);
break;
}
case '-': {
if (strncmp("ver", argv[i] + 2, 3) == 0) {
printVers(progName);
printf("\n");
if (makeArgc == 0) {
if (i >= (argc - 1)) {
exit(0);
}
/* eat this opt if cmd isn't specified yet */
break;
}
}
/* FALL THROUGH */
}
default: {
makeArgv[makeArgc++] = argv[i];
break;
}
}
}
else {
if (strncmp("XDCPATH=", argv[i], 8) == 0) {
xdcPathDef = argv[i];
}
makeArgv[makeArgc++] = argv[i];
}
}
if (makeArgv[0] == NULL) {
fprintf(stderr, usage, progName);
exit(1);
}
/* compute expanded package path */
packagePath = getPackagePath(xdcPathDef);
/* if we can't find make in XDCROOT/bin, try alternatives */
if (access(makeArgv[0], 00) != 0) {
String cmd = findFile(makeArgv[0], packagePath);
if (cmd == NULL) {
fprintf(stderr, "%s: can't find '%s' along the path %s\n",
progName, makeArgv[0], packagePath);
exit(1);
}
}
/* set PATH in environment before executing or displaying command */
envp = genEnvp(xdcRoot, envp);
/* if verbose flag is set, display the commands to be executed */
if (nflag == TRUE || verbose >= 1) {
if (verbose >= 2) {
for (i = 0; envp[i] != NULL; i++) {
printf("%s\n", envp[i]);
}
printf("\n");
}
/* display the make command */
for (i = 0; i < makeArgc; i++) {
if (i > 0 && strpbrk(makeArgv[i], " \t") != NULL) {
printf("\"%s\" ", makeArgv[i]);
}
else {
printf("%s ", makeArgv[i]);
}
}
printf("\n");
}
if (nflag == FALSE) {
/* execute make command */
if ((status = XUTL_run(makeArgv[0], makeArgv, envp))) {
fprintf(stderr, "%s: can't execute '%s' ", progName, makeArgv[0]);
perror("because");
}
}
/* if the exec failed, return its error status */
return (status);
}
/*
* ======== d2u ========
* Convert DOS path string into unix path string
*/
static Void d2u(String buf)
{
Char *cp;
for (cp = buf; *cp != '\0'; cp++) {
if (*cp == '\\') {
*cp = '/';
}
}
}
/*
* ======== findFile ========
*/
static String findFile(String file, String path)
{
static Char nameBuf[MAXNAME + 1];
String pathBuf = NULL;
String tmp;
Int len;
/* if the nameBuf is too small we fail */
if (file == NULL || (len = strlen(file)) > MAXNAME) {
return (NULL);
}
/* if file is a full path name, test it unadorned */
if (file[0] == DIRSTR[0] || file[1] == ':') {
if (isFile(nameBuf)) {
strcpy(nameBuf, file);
return (nameBuf);
}
}
if (path == NULL) {
return (NULL);
}
/* otherwise, try every prefix in path */
if ((pathBuf = (Char *)malloc(strlen(path) + 1)) != NULL) {
strcpy(pathBuf, path);
tmp = strtok(pathBuf, PATHSTR);
for (; tmp != NULL; tmp = strtok(NULL, PATHSTR)) {
if ((len + 1 + strlen(tmp)) <= MAXNAME) {
sprintf(nameBuf, "%s%s%s", tmp, DIRSTR, file);
if (isFile(nameBuf)) {
free(pathBuf);
return (nameBuf);
}
}
}
free(pathBuf);
}
return (NULL);
}
/*
* ======== genEnvp ========
* Generates environment for build tools:
* o Add xdcRoot to the beginning of PATH environment variable to ensure
* that our build tools are used within make.
* o remove CLASSPATH from environment to avoid in appropriate
* versions of Java or Java classes.
* o remove ENV to prevent shell from executing commands in the
* file named by $ENV for every shell use by gmake. It is for
* performance purposes only.
* o remove MAKEFLAGS to prevent xdc's make from reading make options
* set by a make calling xdc; e.g., the silent flag will prevent
* XDCOPTIONS=v from doing what is expected.
* o remove MAKELEVEL to prevent xdc's make from getting confused
* by a make calling xdc; e.g., a non-zero MAKELEVEL triggers
* the "print directories" feature (unless explicitly disabled)
*/
static char **genEnvp(String xdcRoot, char *envp[])
{
Int i, j;
Int envc;
char **newEnvp = NULL;
/* re-define selected environment variables */
for (i = 0; envp[i] != NULL; i++) {
/* redefine XDCROOT (if necessary) */
if (strncmp("XDCROOT=", envp[i], 8) == 0) {
envp[i] = rootDef;
if (nflag) {
printSetEnv(envp[i]);
}
}
else if (xdcPathDef != NULL && strncmp("XDCPATH=", envp[i], 8) == 0) {
/* we need to put XDCPATH in the environment because GNU make
* does not set the environment for commands run via $(shell ...)
* and we want all such commands to see the path specified in
* the command line
*/
envp[i] = xdcPathDef;
xdcPathDef = NULL;
if (nflag) {
printSetEnv(envp[i]);
}
}
else {
/* redefine PATH */
String prefix[] = {"PATH=", "Path="};
for (j = 0; j < (sizeof(prefix) / sizeof(String)); j++) {
if (strncmp(prefix[j], envp[i], strlen(prefix[j])) == 0) {
String path;
String mach;
Int len = strlen(envp[i]) + strlen(xdcRoot) + 32;
if ((path = (String)malloc(len)) == NULL) {
fprintf(stderr, "%s: out of memory\n", progName);
exit(1);
}
if ((mach = getenv("_M")) != NULL) {
sprintf(path, "%s" DIRSTR "bin%s", xdcRoot, mach);
if (access(path, 00) != 0) {
mach = "";
}
}
else {
mach = "";
}
sprintf(path, "%s%s" DIRSTR "bin%s" PATHSTR "%s",
prefix[j], xdcRoot, mach, envp[i] + strlen(prefix[j]));
envp[i] = path;
if (nflag) {
printSetEnv(envp[i]);
}
}
}
}
}
/* remove undesirable environment variables */
for (envc = i = 0; envp[i] != NULL; i++) {
String removeTab[] = {
"CLASSPATH=",
"ENV=",
"MAKELEVEL=", "MAKEFLAGS="
};
for (j = 0; j < (sizeof(removeTab) / sizeof(String)); j++) {
if (strncmp(removeTab[j], envp[i], strlen(removeTab[j])) == 0) {
if (nflag) {
printSetEnv(removeTab[j]);
}
break;
}
}
/* if envp[i] is not in the undesirable list, add it to the env */
if (j >= (sizeof(removeTab) / sizeof(String))) {
envp[envc++] = envp[i];
}
}
/* create a new environment array (so we can add new definitions) */
if ((newEnvp = malloc((envc + MAXNEW + 1) * sizeof(String))) == NULL) {
fprintf(stderr, "%s: out of memory\n", progName);
exit(1);
}
memcpy(newEnvp, envp, envc * sizeof(String));
/* add XDCPATH definition, if necessary */
if (xdcPathDef != NULL) {
newEnvp[envc++] = xdcPathDef;
}
/* NULL terminate and return new environment array */
newEnvp[envc] = NULL;
return (newEnvp);
}
#if 0
/*
* ======== getHostName ========
*/
static String getHostName(Void)
{
static Char name[MAXNAME + 1];
#if defined(xdc_target__os_Windows)
static Bool init = FALSE;
if (init == FALSE) {
WSADATA wsaData;
init = TRUE;
if ( WSAStartup( MAKEWORD( 1, 1 ), &wsaData) != 0 ) {
/* we could not find a usable WinSock DLL. */
return("");
}
}
#endif
if (gethostname(name, MAXNAME) != 0) {
return("");
}
name[MAXNAME] = '\0';
return (name);
}
#endif
/*
* ======== getPackagePath ========
*/
static String getPackagePath(String xdcPath)
{
String result = NULL;
String fullPath;
Int len;
if (xdcPath == NULL) {
xdcPath = "";
}
len = strlen(xdcPath) + strlen(xdcRoot) + 32;
if ((fullPath = (String)malloc(len * sizeof (char))) != NULL) {
sprintf(fullPath, "%s;%s;^", xdcPath, xdcRoot);
result = XUTL_expandPath(fullPath, ".", TRUE);
free(fullPath);
}
return (result);
}
/*
* ======== isFile ========
* Return TRUE iff name exists and is not a directory
*/
static Bool isFile(String name)
{
struct stat buf;
if (stat(name, &buf) == 0 && !S_ISDIR(buf.st_mode)) {
return (TRUE);
}
return (FALSE);
}
/*
* ======== printSetEnv ========
*/
static Void printSetEnv(String env)
{
printf("set %s\n", env);
}
/*
* ======== printVers ========
*/
static Void printVers(String progName)
{
fprintf(stderr, "%s: version %s, %s\n", progName,
TISB_TREENAME, __DATE__);
}