github.com/jchengjr77/canaveral@v1.0.1-0.20200715160102-ea9245d1a2fb/csupport/addC.go (about)

     1  package csupport
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"strings"
     9  
    10  	"github.com/jchengjr77/canaveral/lib"
    11  )
    12  
    13  // createMainFile creates a basic projName.c file that uses stdlib.h
    14  // to print "Canaveral is awesome!" in the main function
    15  // * tested
    16  func createMainFile(projName string) error {
    17  	err := lib.CreateFile(projName + ".c")
    18  	if err != nil {
    19  		return err
    20  	}
    21  	mainfile, err := os.OpenFile(projName+".c", os.O_APPEND|os.O_WRONLY, 0644)
    22  	defer func() {
    23  		err := mainfile.Close()
    24  		lib.Check(err)
    25  	}()
    26  
    27  	include := "#include <stdio.h>"
    28  	main := "int main() {\n\tprintf(\"Canaveral is awesome!" + `\n` + "\");\n\treturn 0;\n}\n"
    29  
    30  	_, err = mainfile.WriteString(include + "\n\n" + main)
    31  	return err
    32  }
    33  
    34  // createREADME creates a README.md file
    35  // * tested
    36  func createREADME(projName string) error {
    37  	err := lib.CreateFile("README.md")
    38  	if err != nil {
    39  		return err
    40  	}
    41  	readme, err := os.OpenFile("README.md", os.O_APPEND|os.O_WRONLY, 0644)
    42  	defer func() {
    43  		err := readme.Close()
    44  		lib.Check(err)
    45  	}()
    46  	header := "# " + projName
    47  	making := "## Compiling\nTo compile " + projName + "simply download it and run `make`. To clean old builds, run `make clean`"
    48  	canaveral := "###### Created with [Canaveral](https://github.com/jchengjr77/canaveral)"
    49  	_, err = readme.WriteString(header + "\n\n" + making + "\n\n" + canaveral)
    50  	return err
    51  }
    52  
    53  // createMakeFile creates a make file that compiles the projName.c file into
    54  // a binary called projName
    55  // * tested
    56  func createMakeFile(projName string) error {
    57  	err := lib.CreateFile("Makefile")
    58  	if err != nil {
    59  		return err
    60  	}
    61  
    62  	make, err := os.OpenFile("Makefile", os.O_APPEND|os.O_WRONLY, 0644)
    63  	defer func() {
    64  		err := make.Close()
    65  		lib.Check(err)
    66  	}()
    67  	topComment := "# Basic makefile generated by Canaveral"
    68  	CC := "CC = gcc"
    69  	CFLAGS := "CFLAGS = -g -Og -Wall -std=c99 -I."
    70  	DEPS := "DEPS = " + projName + ".h"
    71  	oFiles := "%.o: %.c $(DEPS)\n\t$(CC) -c -o $@ $< $(CFLAGS)"
    72  	outfile := projName + ": " + projName + ".o\n\t$(CC) -o $@ $^ $(CFLAGS)"
    73  	PHONY := ".PHONY: clean"
    74  	clean := "clean:\n\trm -f *.o *~"
    75  
    76  	_, err = make.WriteString(topComment + "\n\n" + CC + "\n" + CFLAGS + "\n" + DEPS + "\n\n" + oFiles + "\n\n" + outfile + "\n\n" + PHONY + "\n" + clean)
    77  	return err
    78  }
    79  
    80  // AddToMake adds a dependency to a Makefile conforming to the style of the one
    81  // created by canaveral. It takes in [filename].c, adds [filename].h to the
    82  // DEPS definition and [filename].o to the make definition for the binary file
    83  // [binaryAddTo] line of the form [binaryAddTo]: [file].o
    84  // * tested
    85  func AddToMake(filename, binaryAddTo string) error {
    86  	if !lib.FileExists(filename) {
    87  		return errors.New("File not found: " + filename)
    88  	}
    89  	if len(filename) < 2 || filename[len(filename)-2:] != ".c" {
    90  		return errors.New("Currently addmake only supports adding simple rules for compiling additional c files")
    91  	}
    92  	if !lib.FileExists("Makefile") {
    93  		return errors.New("Cannot find Makefile")
    94  	}
    95  	makefile, err := ioutil.ReadFile("Makefile")
    96  	if err != nil {
    97  		return err
    98  	}
    99  
   100  	addedDependency := false
   101  	addedOutfile := false
   102  
   103  	lines := strings.Split(string(makefile), "\n")
   104  	for i, line := range lines {
   105  		if len(line) >= 4 && line[0:4] == "DEPS" {
   106  			addedDependency = true
   107  			lines[i] = line + " " + filename[:len(filename)-2] + ".h"
   108  		}
   109  		if len(line) >= len(binaryAddTo) && line[:len(binaryAddTo)] == binaryAddTo {
   110  			addedOutfile = true
   111  			lines[i] = line + " " + filename[:len(filename)-2] + ".o"
   112  		}
   113  	}
   114  
   115  	if addedDependency && addedOutfile {
   116  		output := strings.Join(lines, "\n")
   117  		err = ioutil.WriteFile("Makefile", []byte(output), 0644)
   118  		return err
   119  	}
   120  	if !addedDependency {
   121  		return errors.New("Currently addmake only supports very simple Makefile additions, and the found Makefile doesn't conform to the necessary standards. Missing line: DEPS [file].h")
   122  	}
   123  	return errors.New("Currently addmake only supports very simple Makefile additions, and the found Makefile doesn't conform to the necessary standards. Missing line: " + binaryAddTo + ": [file].o")
   124  }
   125  
   126  // AddCProj launches a new C project.
   127  // The main mechanism is similar to addProj (in root folder).
   128  // It will create a Makefile, projName.c, and a projName.h file
   129  // * tested
   130  func AddCProj(projName string, wsPath string) {
   131  	// Get workspace path
   132  	ws, err := ioutil.ReadFile(wsPath)
   133  	lib.Check(err)
   134  	err = os.MkdirAll(string(ws)+"/"+projName, os.ModePerm)
   135  	lib.Check(err)
   136  	// Navigate to canaveral workspace
   137  	err = os.Chdir(string(ws) + "/" + projName)
   138  	lib.Check(err)
   139  
   140  	err = createMainFile(projName)
   141  	lib.Check(err)
   142  	err = lib.CreateFile(projName + ".h")
   143  	lib.Check(err)
   144  	err = createMakeFile(projName)
   145  	lib.Check(err)
   146  	err = createREADME(projName)
   147  	lib.Check(err)
   148  
   149  	fmt.Printf("Added C Project %s to workspace %s\n", projName, string(ws))
   150  }