Loading repository data…
Loading repository data…
dariokozicki / repository
Guía para setear un proyecto básico en VSCode en C, para la materia de Sistemas Operativos
makefile:35: *** missing separator. Stop.
Es porque Markdown alteró los tabs. Necesitas sacar el espacio de las acciones, poner tab en cada uno, y probar nuevamente.
Primero creamos una carpeta para cada uno de los procesos que nos piden, más una llamada 'shared' donde va a estar el código compartido. (Vamos a hacer una trampita: no es realmente una biblioteca compartida.)
proceso1 proceso2 proceso3 shared
Vamos a abrir VSCode e ir a Archivo->Abrir Carpeta, y seleccionamos todas estas carpetas, con shift. Luego hacemos archivo->guardar área de trabajo como... y se nos va a crear un archivo .code-workspace en la ruta del TP.
La proxima vez que lo queramos abrir, vamos a hacer Archivo->Abrir Área de Trabajo, seleccionando ese .code-workspace, y nos va a abrir todas las carpetas de una con sus configuraciones.
En cada una de estas carpetas, creamos las subcarpetas:
obj src include cfg .vscode
En src van a estar nuestros .c, en include nuestros .h, en cfg nuestras configuraciones y logs, y en obj van a estar los .o (no vamos a interactuar con éstos). Shared no necesita cfg.
.vscode es una carpeta de VSC que va a ser más útil en breve.
A continuación, vamos a copiar el siguiente makefile en cada uno de los procesos excepto shared, reemplazando el valor de PROCESS_NAME con el de nuestro proceso
PROCESS_NAME=proceso1
IDIR =./include
SHARED_IDIR = ../shared/include
CC=gcc
CFLAGS=-I$(IDIR) -I$(SHARED_IDIR) -g -Wall
ODIR=./obj
SRCDIR =./src
LIBS=-lcommons -lpthread -lreadline -lcunit -lrt
SHARED_SRCDIR = ../shared/src
SHARED_ODIR = ../shared/obj
DEPS = $(wildcard $(IDIR)/*.h)
SRC = $(wildcard $(SRCDIR)/*.c)
OBJ = $(patsubst $(SRCDIR)/%.c,$(ODIR)/%.o,$(SRC))
$(ODIR)/%.o: $(SRCDIR)/%.c $(DEPS) $(SHARED_DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
$(SHARED_ODIR)/%.o: $(SHARED_SRCDIR)/%.c $(SHARED_DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
SHARED_DEPS = $(wildcard $(SHARED_IDIR)/*.h)
SHARED_SRC = $(wildcard $(SHARED_SRCDIR)/*.c)
SHARED_OBJ = $(patsubst $(SHARED_SRCDIR)/%.c,$(SHARED_ODIR)/%.o,$(SHARED_SRC))
$(PROCESS_NAME): $(OBJ) $(SHARED_OBJ)
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~ $(PROCESS_NAME) $(SHARED_ODIR)/*.o
Los makefiles constan de macros y reglas. Las macros tienen el formato:
MACRO=valor
y podemos poner paths, comandos, nombres, includes y mucho más, evitando repetirlo después y referenciándolo con el formato $(MACRO). A su vez, los makefiles tienen reglas, que tienen el formato:
target: dependencias
acción
Donde acción debe tener un TAB sí o sí. Target es el nombre de la regla que podemos usar en la terminal (make clean, make install, etc), Dependencias son las que necesito para ejecutar la acción, como los .o que necesito para armar el ejecutable. Acción es el comando que quiero ejecutar, como gcc con los argumentos y las dependencias. Este makefile lo hice siguiendo esta guía de la prehistoria y si querés modificarlo a tu gusto te invito a leer la documentación.
LIBS es un macro donde van las librerías que vamos a usar. -lcommons es la de la cátedra, -cunit es para los tests unitarios (optativo), y los demás los necesité en su momento. Agregá o sacá de acuerdo a tus necesidades.
CFLAGS es un macro donde van los flags al compilar. -g es necesario para ejecutar en VSCode en modo debug. -Wall es para mostrar todos los warnings. Te recomiendo no sacar ninguno.
Este makefile nos va a permitir que el procesoN compile utilizando los .c y .h del proceso más los que están en la shared. Acá está la trampita; no es una biblioteca compartida sino un lugar donde los procesos saben que tienen que ir a buscar el resto de los archivos.
En /src/ vamos a crear nombreproceso.c y en /include/ nombreproceso.h.
#include "proceso1.h"
int main(){
t_log* logger = log_create("./cfg/proceso1.log", "PROCESO1", true, LOG_LEVEL_INFO);
log_info(logger, "Soy el proceso 1! %s", mi_funcion_compartida());
log_destroy(logger);
}
#ifndef PROCESO1_H
#define PROCESO1_H
#include <stdio.h>
#include <commons/log.h>
#include <stdbool.h>
#include "shared_utils.h"
#endif
Podes ver la docu si no entendés el código. Igualmente lo vas a ver en el TP0.
Vamos a agregar dos archivos más en la carpeta shared
#ifndef SHARED_UTILS_H
#define SHARED_UTILS_H
#include <stdio.h>
#include <commons/log.h>
#include <stdbool.h>
char* mi_funcion_compartida();
#endif
#include "shared_utils.h"
char* mi_funcion_compartida(){
return "Hice uso de la shared!";
}
Si hacemos make vamos a ver que se nos creó el ejecutable. Hurra!
>make && ./proceso1
make: 'proceso1' is up to date.
[INFO] 17:14:17:572 PROCESO1/(16977:16977): Soy el proceso 1! Hice uso de la shared!
Seguro te está desmotivando tener que hacer make y ./miproyecto cada vez que querés probar tu programa. Y el botoncito de Eclipse para correr con valgrind (o de manera normal!) ni está.
'Me están cagando'. Dijo, mientras perdía la esperanza.
Vamos a crear dos shell scripts en cada proceso, cambiando el valor de FILE por el nombre de nuestro proceso:
#!/bin/bash
FILE=proceso1
make $FILE
if test -f "./$FILE"; then
./$FILE
fi
#!/bin/bash
FILE=proceso1
make $FILE
if test -f "./$FILE"; then
valgrind --tool=memcheck --leak-check=yes --show-possibly-lost=no --show-reachable=no --num-callers=20 ./$FILE
fi
A partir de esto, en la terminal podemos escribir ./exec o ./vexec para Compilar y Ejecutar el proceso en un solo paso, ya sea normalmente o con valgrind. Optativamente podemos agregar un script para helgrind:
#!/bin/bash
FILE=proceso1
make $FILE
if test -f "./$FILE"; then
valgrind --tool=helgrind ./$FILE
fi
Si queremos que esté más ordenado, podemos agregar --log-file=a.out antes de ./$FILE y así lo importante va a irse a un archivo aparte
Para ejecutar estos scripts, pero vamos a tener que darnos permiso de ejecución. Para esto vamos a escribir
chmod 777 exec
y así con vexec y hexec. Pero en VSC todavía nos faltan algunas cosas. Nota: Ni se les ocurra hacer esto fuera de la VM o del TP
Habrás observado que, si bien compila y todo, VSCode te subraya en verde algunos imports. Esto es porque, si bien vos, yo y el makefile sabemos dónde están los headers (.h), VSCode no tiene ni idea de cómo organizamos el proyecto.
Dentro de /.vscode/, creamos el archivo c_cpp_properties.json con el siguiente contenido:
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}",
"/usr/include/c++/5",
"/usr/include/i386-linux-gnu/c++/5",
"/usr/include/c++/5/backward",
"/usr/lib/gcc/i686-linux-gnu/5/include",
"/usr/local/include",
"/usr/lib/gcc/i686-linux-gnu/5/include-fixed",
"/usr/include/i386-linux-gnu",
"/usr/include",
"${workspaceFolder}/include",
"../shared/include"
],
"defines": ["_GNU_SOURCE"],
"intelliSenseMode": "clang-x86",
"browse": {
"path": [
"${workspaceFolder}",
"${workspaceFolder}/include",
"../shared/include",
"/usr/include/c++/5",
"/usr/include/i386-linux-gnu/c++/5",
"/usr/include/c++/5/backward",
"/usr/lib/gcc/i686-linux-gnu/5/include",
"/usr/local/include",
"/usr/lib/gcc/i686-linux-gnu/5/include-fixed",
"/usr/include/i386-linux-gnu",
"/usr/include"
],
"limitSymbolsToIncludedHeaders": true,
"databaseFilename": ""
},
"compilerPath": "/usr/bin/gcc",
"cStandard": "c11",
"cppStandard": "c++17"
}
],
"version": 3
}
Con esto le hacemos saber a VSC que tiene que buscar en el /include/ del proyecto y en el /include/ de la shared. Los warnings en verde deberían irse.
Todo bien, pero me dijiste que podía usar VSCode y tengo que usar exec, vexec y no sé qué. Al final sigo usando la terminal.
Vamos a la parte de Debug de VSC (bichito a la izquierda en el IDE), y arriba donde aparece "DEPURAR" vamos a abrir el combo box y seleccionar Agregar Configuración (procesoN). Seleccionamos C++ (GDB/LLDB), y "Launch".
Se nos va a abrir launch.json en /.vscode/ . Vamos a cambiar (gdb) Launch en name por Proceso1, y lo de program por ${workspaceFolder}/proceso1
Ahora ya podemos Debuggear nuestro proyecto! Si vas al bichito nue