New to makefiles - no clue how to make it work - c

When compiling my program, the makefile outputs this error:
cc sherpa.c -o -O2 -Wall
sherpa.c:4:10: fatal error: vte/vte.h: No such file or directory
was gonna post the code here but the formatting is weird so here's the github link https://github.com/amogus3016/sherpa
EDIT: code below
// Sherpa Terminal Emulator //
// This program is licensed under the GNU GPL 3.0, which provides absolutely NO WARRANTY //
__________________
| |
| // |
| // |
| // |
| // |
| // |
|________________|
#include <vte/vte.h>
static void
child_ready(VteTerminal *terminal, GPid pid, GError *error, gpointer user_Data)
{
if (!terminal) return;
if (pid == -1) gtk_main_quit();
}
int
main(int argc, char *argv[])
{
GtkWidget *window, *terminal;
/* init gtk window and terminal */
gtk_init(&argc, &argv);
terminal = vte_terminal_new();
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "Sherpa");
/* start new shell */
gchar **envp = g_get_environ();
gchar **command = (gchar *[]){g_strdup(g_environ_getenv(envp, "SHELL")), NULL };
g_strfreev(envp);
vte_terminal_spawn_async(VTE_TERMINAL(terminal),
VTE_PTY_DEFAULT,
NULL, /* working dir */
command, /* command */
NULL, /* environment */
0, /* spawn flags */
NULL, NULL, /* child setup */
NULL, /* child pid */
-1, /* timeout */
NULL, /* cancellable */
child_ready, /* callback */
NULL); /* user_data */
/* connect signals */
g_signal_connect(window, "delete-event", gtk_main_quit, NULL);
g_signal_connect(terminal, "child-exited", gtk_main_quit, NULL);
/* combine widgets and run main loop */
gtk_container_add(GTK_CONTAINER(window), terminal);
gtk_widget_show_all(window);
gtk_main();
}
and the makefile:
sherpa: sherpa.c
$(CC) sherpa.c -o -O2 -Wall
printf("Building executable [|]")
printf("Building executable [/]")
printf("Building executable [-]")
printf("Building executable [\]")
printf("Building executable [|]")
mv ./sherpa /usr/bin
printf("Installing [|]")
printf("Installing [/]")
printf("Installing [-]")
printf("Installing [\]")
printf("Installing [|]")

IMO, you should rely on the default rules that make uses. In your case, since you are building an executable named sherpa from a file named sherpa.c, you can pretty much rely on the built-in rules for everything. The only thing atypical you are doing is using mv to install the executable, and the more typical usage would be to put that in a separate rule. In other words, your entire Makefile could simply be:
CFLAGS += $$(pkg-config --cflags vte-2.91)
LDFLAGS += $$(pkg-config --libs vte-2.91)
.PHONY: install all
all: sherpa
install: sherpa
mv ./sherpa /usr/bin
If you don't include the install recipe (which, IMO, you should not. Installing a package should have more infrastructure than merely copying the executable to /usr/bin), you can delete the last 4 lines of the file. (This would require that the user type make sherpa instead of just make, so keeping all: sherpa is reasonable, but you don't need to specify the build command.)
By using += when assigning CFLAGS and LDFLAGS, you allow the user to add flags at run time. eg, you can invoke CFLAGS='-g -O2' make to build the executable with optimizations enabled.

Related

Can't run shell command in VTE GTK4 Fake Terminal

I made a small sample code in gtk4 + vte to run a fake terminal with a button in the bottom to run a simple command when the button is clicked.
main.c
#include <gtk/gtk.h>
#include <vte/vte.h>
#define WINDOW_HEIGHT 400
#define WINDOW_WIDTH 600
GtkApplication *app;
GtkWidget *window, *terminal, *grid, *scrollview1,*button;
int status;
void run_button(void){
char **argv_test[2] = {
"echo\0",
"Hello!!\0"
};
// can't run this command in fake terminal!
vte_terminal_spawn_async(VTE_TERMINAL(terminal),VTE_PTY_NO_HELPER,NULL,argv_test,NULL,G_SPAWN_SEARCH_PATH,NULL,NULL,NULL,2000,NULL,NULL,NULL);
}
void window_renderer(GtkApplication *app, gpointer user_data) {
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window),"My terminal");
gtk_window_set_default_size (GTK_WINDOW(window), WINDOW_WIDTH, WINDOW_HEIGHT);
grid = gtk_grid_new();
gtk_window_set_child(GTK_WINDOW(window), grid);
gtk_widget_set_vexpand(grid,TRUE);
gtk_widget_set_hexpand(grid,TRUE);
scrollview1 = gtk_scrolled_window_new();
gtk_grid_attach(GTK_GRID(grid), scrollview1, 0, 0, 1, 1);
gtk_widget_set_size_request(GTK_WIDGET(scrollview1),WINDOW_WIDTH,WINDOW_HEIGHT);
button = gtk_button_new_with_label("Run!");
gtk_grid_attach(GTK_GRID(grid), button, 0, 1, 1, 1);
g_signal_connect(button,"clicked", G_CALLBACK(run_button), NULL);
terminal = vte_terminal_new();
gtk_window_set_child(GTK_WINDOW(scrollview1), terminal);
gtk_widget_show(window);
}
int main(int argc, char **argv)
{
app = gtk_application_new(NULL, G_APPLICATION_FLAGS_NONE);
g_signal_connect(app,"activate", G_CALLBACK(window_renderer), NULL);
status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
Makefile
CFLAGS += -Wall
CFLAGS += `pkg-config --cflags gtk4 vte-2.91-gtk4`
LIBS += `pkg-config --libs gtk4 vte-2.91-gtk4`
.PHONY: all clean
all: main
main:main.c
gcc $(CFLAGS) main.c -o main $(LIBS)
clean:
rm main
I have compiled VTE (for gtk4) and gtk4 developer package, building a gtk4 app is not an issue!
When running the built binary, the program crashes when I click the button with a segmentation fault, probably because of a pointer not properly initialized (according to tutorials point).
Can someone help me to find out what I have missed?
I tested out your code and I believe I found the main issue with your terminal command along with some warnings that were displayed when I tested. First off, from reviewing other sample code using the "vte_terminal_spawn_async" function, the character string set included an ending array element of "NULL". So instead of the following code snippet.
char **argv_test[2] = {
"echo\0",
"Hello!!\0"
};
You would need to add in a third array element as in the following revised code snippet.
char *argv_test[3] = {
"echo\0", "Hello!!\0", NULL
};
If you notice one other minor revision to the above code snippet, I revised the definition of the character array from "char ** argv_test[3]" to "char *argv_test[3]". The compiler was listing a warning about incompatible pointer references. Also, when I was testing out this code I was receiving a warning and not able to view the terminal when the "Run" button was clicked.
Gtk-CRITICAL **: 14:49:46.383: gtk_window_set_child: assertion 'GTK_IS_WINDOW (window)' failed
From some previous troubleshooting with another user, we had determined that the child setup for the scrolled window needed to utilize the scrolled window child reference function along with the scrolled window macro. So I revised the scrolled window child assignment to be as follows.
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrollview1), terminal);
Making those small revisions resulted in displaying the terminal with your "echo Hello" command (I clicked the button twice in my testing).
I believe that if you try out those minor revisions to your code, you will be able to view your terminal and progress with your coding.
Regards.

Setting the title of a Motif Window

I am trying to set the title of a toplevel Motif 2.1 window.
From O'Reilly Volume Six A, I have seen that in Motif 2.1 XtVaOpenApplication is recommended to create a toplevel Widget.
In this appendix it can be seen how options and XtNumber(options) are used to act on resources via argument list.
I have tried to use it to generate an optional flag -title WINDOW_TITLE while invoking the program, without sucess.
This is what I have tried:
#include <stdlib.h>
#include <stdio.h>
#include <Xm/Xm.h>
#include <Xm/PushB.h>
static XrmOptionDescRec options[] = {
{ "-title", "XmNtitle", XrmoptionIsArg, NULL },
};
int main(int argc, char *argv[]) {
Widget toplevel; /* Top Level Button */
XtAppContext app; /* Application Context */
char *window_title = NULL; /* Top Level Window Title */
/* INITIALIZE TOP LEVEL WINDOW */
XtSetLanguageProc(NULL, NULL, NULL);
toplevel = XtVaOpenApplication( &app, argv[0], options, XtNumber(options), &argc, argv, NULL, sessionShellWidgetClass, NULL);
/* REALIZE TOPLEVEL WINDOW AND LAUNCH APPLICATION LOOP */
XtRealizeWidget(toplevel);
XtAppMainLoop(app);
return 0;
}
The program compiles but it does not react to -title MYTITLE command line argument.
This is the makefile (works on FreeBSD 12):
test: test.o
cc -L/usr/local/lib -O -o test test.o -lXm -lXt -lX11
test.o: test.c
cc -I/usr/local/include -c test.c
How can I change the title of the window based on an optional argument named -title?
The correct xrm option line is
{"-title", ".title", XrmoptionSepArg, NULL}
You don't actually need to specify it because it is in the default Xt option table.
In general you omit XmN when specifying xrm resource names.
In my Motif programs, I use Xlib directly, since Motif does not seem to handle correctly the UTF8 setting of window titles using XmNtitle property. Most modern window managers expect UTF8 string passed as _NET_MW_NAME.
void setWindowTitleUTF8(Widget w, char *title)
{
static Atom atoms[3];
static bool first = TRUE;
if (first)
{
static char *atom_names[] = {"_NET_WM_NAME", "_NET_WM_ICON", "UTF8_STRING"};
first = FALSE;
XInternAtoms(XtDisplay(w), atom_names, 3, FALSE, atoms);
}
XChangeProperty(XtDisplay(w), XtWindow(w), atoms[_NET_WM_NAME], atoms[UTF8_STRING], 8,
PropModeReplace, (unsigned char *) title, strlen(title));
}
Make sure you call it on XtParent() of your widget, so it is applied to top level widget shell.
Please investigate further yourself (I'm no X/Motif expert), but sth seems to be off with the argument parsing.
Replacing options with NULL ant its size with 0 in call XtVaOpenApplication call seems to do the trick:
toplevel = XtVaOpenApplication( &app, argv[0], NULL, 0, &argc, argv, NULL, sessionShellWidgetClass, NULL);

Getting keyboard modifiers state using Gnome libs (GDK) fetches initial state only

I'm trying to get the current keyboard modifiers state through gnome GDK or GTK library in aim to implement an accessibility gnome shell extension that shows that state.
I know how to get thier state using xlib, but there is not full binding for gnome gjs.
The code below get only the initial state. It does not update state.
/*
* compiling: gcc `pkg-config --cflags gdk-3.0` -o gdk_mod gdk_mod.c `pkg-config --libs gdk-3.0`
*/
#include <gdk/gdk.h>
int main (int argc, char **argv) {
gdk_init(&argc, &argv);
GdkDisplay * disp;
disp = gdk_display_open(NULL);
if (disp!=NULL) g_printf("display connected!\n");
GdkKeymap * kmap;
kmap = gdk_keymap_get_for_display(disp);
guint state;
state = gdk_keymap_get_modifier_state(kmap);
g_printf("mod state: %x\n", state);
while (1) {
g_usleep(1000000);
//kmap = gdk_keymap_get_for_display(disp);
state = gdk_keymap_get_modifier_state(kmap);
g_printf("mod state: %x\n", state);
}
}
Here an example output with CAPS lock active then inactive but no change:
$ ./gdk_mod
display found!
mod state: 2
mod state: 2
mod state: 2
mod state: 2
mod state: 2
^C
Currently using Kubuntu 15.04.
What's wrong with my code?
You are going to need to run the GTK+ event loop for this to work. The event loop is part of GLib's main loop. When you call gtk_main(), this main loop is run. I don't know if it polls for events or has events pushed to it, but it won't ask for the keyboard state on the fly like you were trying to do.
The easiest way to set up GDK is to do it via GTK+ by using gtk_init() and gtk_main(). You can use GDK on its own, but I don't know how. You seemed to have figured it out, which works.
And instead of calling g_usleep(), which just blocks your program, you can hook a periodic timeout into the main loop. This is done with g_timeout_add(). The function that you pass to g_timeout_add() returns a Boolean value that decides whether the timer should be stopped or not, so you don't have to worry about rescheduling your function, as GLib will do that for you.
Indeed, I need an event loop as andlabs said in his comment. His suggestion to use GTK gtk_init() & gtk_main() works perfectly.
/*
* compiling: gcc `pkg-config --cflags gtk+-3.0` -o gtk_xkbmod3 gtk_xkbmod3.c `pkg-config --libs gtk+-3.0`
*/
#include <gtk/gtk.h>
static void update(GdkKeymap * kmap) {
guint state;
state = gdk_keymap_get_modifier_state(kmap);
g_printf("%i\n", state);
}
int main (int argc, char **argv) {
gtk_init(&argc, &argv);
GdkKeymap * kmap;
kmap = gdk_keymap_get_default();
g_timeout_add_seconds(1, (GSourceFunc) update, kmap);
gtk_main();
}
I could also use GDK with GLib GMainLoop.
/*
* compiling: gcc `pkg-config --cflags gdk-3.0` -o gdk_xkbmod4 gdk_xkbmod4.c `pkg-config --libs gdk-3.0`
*/
#include <gdk/gdk.h>
GMainLoop *mainloop;
static void update(GdkKeymap * kmap) {
guint state;
state = gdk_keymap_get_modifier_state(kmap);
g_printf("%i\n", state);
}
int main (int argc, char **argv) {
gdk_init(&argc, &argv);
GdkKeymap * kmap;
kmap = gdk_keymap_get_default();
g_timeout_add_seconds(1, (GSourceFunc) update, kmap);
mainloop = g_main_loop_new(g_main_context_default(), FALSE);
g_main_loop_run(mainloop);
}
References:
Xfce Foundation Classes: The Main Event Loop
GTK+ Forums: GDK + GLib main loop

C Web Browser Download File

WebkitGTK+ API Reference
What I'm trying to do is run my HTML5 app on Linux that way I and my users can still use my app without relying on an internet connection.
My problem is when I go to download say a zip file. The download doesn't execute because there isn't an adequate url for the file to save to (like the desktop). Therefore it doesn't download.
Thus my question relies onto how am I suppose to get an adequate url to download this file when it's executed dynamically via JSZip. (It works fine in Chrome, just not in my app). Terminal says...
source.c:35:3: warning: ‘return’ with a value, in function returning
void [enabled by default] return TRUE; ^
Here's my code:
/*
Save this file as main.c and compile it using this command
(those are backticks, not single quotes):
gcc -Wall -g -o source source.c `pkg-config --cflags --libs gtk+-2.0 webkit-1.0` -export-dynamic
Then execute it using:
./source
If you can't compile chances are you don't have gcc installed.
Install gcc/c with the following terminal command. (This command is for Debian based Linux distros)
sudo apt-get install libgtk2.0-dev libgtk2.0-doc libglib2.0-doc
WebKit requires libraries to successfully aquire, configure, and compile. You can get libraries by issuing the following command in your terminal:
sudo apt-get install subversion gtk-doc-tools autoconf automake libtool libgtk2.0-dev libpango1.0-dev libicu-dev libxslt-dev libsoup2.4-dev libsqlite3-dev gperf bison flex libjpeg62-dev libpng12-dev libxt-dev autotools-dev libgstreamer-plugins-base0.10-dev libenchant-dev libgail-dev
WebkitGTK+ API Reference: http://webkitgtk.org/reference/webkitgtk/stable/webkitgtk-webkitdownload.html
Ubuntu Webkit information - https://help.ubuntu.com/community/WebKit
sudo apt-get install libwebkitgtk-dev python-webkit-dev python-webkit
Required dependencies for this build: (If you installed all the above this is not needed)
sudo apt-get install libgtk2.0-dev libgtk2.0-doc libglib2.0-doc subversion gtk-doc-tools autoconf automake libtool libgtk2.0-dev libpango1.0-dev libicu-dev libxslt-dev libsoup2.4-dev libsqlite3-dev gperf bison flex libjpeg62-dev libpng12-dev libxt-dev autotools-dev libgstreamer-plugins-base0.10-dev libenchant-dev libgail-dev libwebkitgtk-dev
*/
#include <gtk/gtk.h>
#include <webkit/webkit.h>
static void destroy_cb(GtkWidget* widget, gpointer data) {
gtk_main_quit();
}
static void download_requested_cb(WebKitWebView *web_view, WebKitDownload *download) {
const gchar* dest = g_strdup_printf("%s", "file:///home/michael/Downloads/test.zip");
//set the destination uri (eg, send the file to a downloads folder)
webkit_download_set_destination_uri(download, dest);
webkit_download_start();
return TRUE;
}
int main(int argc, char* argv[]) {
GtkWidget* window;
WebKitWebView* web_view;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set_name (window, "AppName");
gtk_window_set_default_size(GTK_WINDOW(window), 600, 600);
//gtk_window_set_icon_from_file(window, "app/logo.png", NULL);
g_signal_connect(window, "destroy", G_CALLBACK(destroy_cb), NULL);
web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
/* Register a callback that gets invoked each time a download is requested */
g_object_connect(web_view, "download-requested", G_CALLBACK(download_requested_cb), NULL);
char uri[PATH_MAX];
char cwd[PATH_MAX];
getcwd(cwd, sizeof(cwd));
if (argc > 1)
snprintf(uri, sizeof(uri), "%s", argv[1]);
else
snprintf(uri, sizeof(uri), "file://%s/app/index.html", cwd);
webkit_web_view_open (web_view, uri);
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(web_view));
gtk_widget_grab_focus(GTK_WIDGET(web_view));
gtk_widget_show_all(window);
gtk_main();
return 0;
}
1) Your basic premise is sound:
file:///home/michael/Downloads/test.zip // This syntax should allow you to "upload" a local file on your hard drve
2) This is a compile warning (not an error). In theory, you could ignore it:
source.c:35:3: warning: ‘return’ with a value, in function returning void [enabled by default] return TRUE; ^
3) This is the problem:
static void download_requested_cb(WebKitWebView *web_view, ...
...
return TRUE; // Delete this line. You can't return anything from a "void" function!
}

Simple multithreaded program segfault

Below is an attempt to write basic multi-threaded program where each thread will read one line from a log file (and does nothing). There is a bug somewhere and program segfaults (no core file generated).
If fgets() is replaced by fscanf() in readInput() then I see a core file. Backtrace is inconsistent and gives different call stack in different core file.
Contents of log file look like:
<num> hello<num>
all numbers less than 100
There are about 90 entries in the log file.
AFAIK, for what this code is doing, we don't need locks. But I put it for later use (and practice).
Can someone please point my mistakes in this code?
threads.h
---------
#include "../../include/global.h"
#include <pthread.h>
#define MAX_LOGS 101
#define NUM_THREADS 10
/* a single record in log file. Read by thread from input stream (file) */
typedef struct __thread_data {
int time; /* time stamp */
char log[32]; /* short log msg */
} thread_data_t;
/* heap (implemented by ordered array) storing the logs */
typedef struct __heap {
thread_data_t entry[MAX_LOGS];
int cur_size; /* used while inserting nodes? */
} heap_t;
add.c
-----
#include "../include/threads.h"
/* Stream from which logs are read (file stream here). Only one thread can
* read at a time */
FILE *fp;
pthread_mutex_t fp_lock;
/* thread start routine */
void *readInput(void *arg)
{
char log[40];
/* get lock for file read */
pthread_mutex_lock(&fp_lock);
/* Critical Section; read file */
if(!feof(fp)) {
fgets(log, 40, fp);
}
/* release lock */
pthread_mutex_unlock(&fp_lock);
pthread_exit(NULL);
}
int pthread_main()
{
int i, ret;
pthread_t threads[NUM_THREADS];
pthread_mutex_init(&fp_lock, NULL);
fp = fopen("logs.txt", "r");
/* error check */
for(i=0; i<NUM_THREADS; i++) {
if(ret = pthread_create(&threads[i], NULL, readInput, NULL)) {
printf("Oops: %s\n", strerror(ret));
return EXIT_FAILURE;
}
}
for(i=0; i<NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
fclose(fp);
return EXIT_SUCCESS;
}
test.c
-------
#include "../include/threads.h"
int main()
{
return pthread_main();
}
Makefile
---------
CC = gcc
CFLAGS = -pthread
OBJFLAGS = -o
STDFLAGS = -std=c99
DBGS = -ggdb -pthread
OBJS = add.o test.o
HEADERS = include/threads.h
SOURCES = src/add.c src/test.c
all: $(OBJS)
$(CC) $(OBJFLAGS) th $(OBJS)
#make clean
$(OBJS): $(SOURCES) $(HEADERS)
$(CC) -c $(DBGS) $(SOURCES)
.PHONY: clean
clean:
rm -rf *.o
Backtrace of core dump.
#0 0x00007fff88d5b68e in pthread_create ()
(gdb) bt
#0 0x00007fff88d5b68e in pthread_create ()
#1 0x00000001051e0cf8 in pthread_main () at add.c:46
#2 0x00000001051e0dbf in main () at test.c:5
(gdb) list
1 #include "../include/threads.h"
2
3 int main()
4 {
5 pthread_main();
6 return 0;
7 }
(gdb) info thread
error on line 787 of "/SourceCache/gdb/gdb-1824/src/gdb/macosx/macosx-nat-infthread.c" in function "void print_thread_info(thread_t, int *)": (ipc/send) invalid destination port (0x10000003)
(gdb) info threads
5 0x00007fff88d47194 in thread_start ()
4 0x00007fff8a15e122 in __psynch_mutexwait ()
3 0x00007fff8a15e122 in __psynch_mutexwait ()
2 0x00007fff88dc242b in flockfile ()
* 1 0x00007fff88d5b68e in pthread_create ()
EDIT1: Thanks for all your feedback. I wanted to keep the actual code concise in original post. But here are the .c and .h files and also the Makefile I am using.
EDIT2: Adding backtrace of core. Line 46 in add.c is pthread_create() routine.
Problem lies in fopen. Code compiles, links and creates an executable correctly. When running it, it failed to open the log file as it could not locate it. I have below file/directory structure. Comment made by #self helped identify the issue.
src/
| Makefile
+--include/
| | threads.h
|
+--src/
| add.c
| test.c
| logs.txt
Either one of the following resolves the issue: (a) Changing the make rule to build executable in src directory and running it that directory. (b) Keep make rule as is but change fopen to point to src/logs.txt.

Resources