how to add library in makefile for verix - batch-file

I want to use makefile to create my app and .out file and use it in my verifone vx520.
I have makeapp.bat for creating .out file but when I run it get this error: NMAKE : fatal error U1073: don't know how to make 'utils.h'
and this is makeapp.bat file:
#goto Begin
:Begin
#set OLDPATH=%PATH%
#rem set VRXSDKS to the Verix V SDK directory
#set VRXSDK=C:\eVoAps\SDK\1.2.0\VRXSDK
#rem Set RVCTDIR to RVDS2.2
#set RVCTDIR=C:\Program Files\ARM\RVCT\Programs\2.2\349\win_32-pentium
#rem or, Set RVCTDIR to RVDS2.1
#rem set RVCTDIR=C:\Program Files\ARM\RVCT\Programs\2.0.1\277\win_32-pentium
#set PATH=%VRXSDK%\bin\;%RVCTDIR%;%OLDPATH%
#rem use app.mak to buid application
nmake /f app.mak
#rem or, use vrxcc directly here to build a simple application
#rem %VRXSDK%\bin\vrxcc app.c
#set PATH=%OLDPATH%
#set RVCTDIR=
pause
how can i solve that error?

So, it looks to me like your bat file here has lots of comments (#rem) and it also sets several variables (#set), but the bulk of the work will be done in the line
nmake /f app.mak
which will reference a different file called app.mak. That's where the magic happens and it's where you will need to edit something to let nmake know how to compile and link utils.h. I suggest you look at c2.com/cgi/wiki?UsingNmake for more details.
As you know, a make file is, for all intents and purposes, a program that you write. When it runs, it builds the VeriFone app (or whatever other program you were working on). As such, there is a multitude of things you can do, some of which you must do if you want nmake to actually build your program. I think the best way to help out would be to share parts of my make file. Note that this started off as just a template from a sample VeriFone project.
Mine starts off just declaring variables, paths, etc., like so:
ProjectName = TestProject
# ****** PATHS ******
# Includes
SDKIncludes = -I$(EVOSDK)\include
ACTIncludes = -I$(EVOACT)include
VCSIncludes = -I$(EVOVCS)include
#Libraries
ACTLibraries = $(EVOACT)OutPut\RV\Files\Static\Release
# App Paths
AppIncludes = .\include
SrcDir = .\source
ObjDir = .\obj
OutDir = .\Output\$(TerminalType)\$(VMACMode)\Files
ResDir = .\Resource
Note that TerminalType is something I have set Visual Studio to pass into NMAKE when it initiates a build and it is based on my solution configuration. Technically, I have 1 make file calling another and the outer one is setting it like this: TerminalType=$(Configuration). You'll see this variable again below as well as a couple others that are similar.
Next, I define some compiler options
# Switch based on terminal type
!IF "$(TerminalType)"=="eVo"
CompilerCompatibility=-p
DefineTerminalType = -DEVO_TERMINAL
!ELSE
CompilerCompatibility=
DefineTerminalType = -DVX_TERMINAL
!ENDIF
The -D flag defines things in my code as if I had done a #define. This is useful for turning parts on or off depending one what I'm compiling for. Unless you plan to do that, you won't need to do it yourself. The important part here for anyone compiling for eVo terminals is the CompilerCompatibility which sets a -p flag (must be off for Verix V, must be on for for eVo terminals).
Now we consolidate everything we've done thus far into 2 variables:
Includes = -I$(AppIncludes) $(SDKIncludes) $(ACTIncludes) $(VMACIncludes) $(VCSIncludes)
COptions =$(CompilerCompatibility) $(DefineTerminalType)
OK, now here's the part I suspect you are tripping up on: we need to define our dependencies, which I do like so:
# Dependencies
AppObjects = \
$(ObjDir)\$(ProjectName).o \
$(ObjDir)\Base.o \
$(ObjDir)\UI.o \
$(ObjDir)\Comm.o
Libs = $(ACTLibraries)\act2000.a
This could all go on one line, if we wanted to. The \ at the end of each line just means we are breaking that single line up which is done here for readability. Otherwise, it would look like this:
AppObjects = $(ObjDir)\$(ProjectName).o $(ObjDir)\Base.o $(ObjDir)\UI.o $(ObjDir)\Comm.o
Libs = $(ACTLibraries)\act2000.a
OK, so this AppObjects will be used when we do our linking. First, however, I also want to tell NMAKE to run the file signing program and then copy the files over where I want them.
# Sign the file(s). Tell nMake that we also
# will be creating the resource file and compiling the actual code...
# NOTE: (the indentations seen below are required for nMake to work properly)
# pseudoOut depends on TestProject.res and TestProject.out.
# If TestProject.res or TestProject.out have changed more recently than pseudoOut,
# then run commands vrxhdr..., filesignature..., and move...
!if "$(VMACMode)"=="Multi"
pseudoOut : $(ResDir)\$(ProjectName).res $(OutDir)\$(ProjectName).out
!else
pseudoOut : $(OutDir)\$(ProjectName).out
!endif
# This calls vrxhdr: the utility program that fixes the executable program’s header required to load and run the program.
# Vrxhdr is needed when you want to move a shared library around on the terminal.
$(EVOSDK)\bin\vrxhdr -s 15000 -h 5000 $(OutDir)\$(ProjectName).out
# do the signing using the file signature tool and the .fst file associated with this TerminalType.
"$(VSFSTOOL)\filesignature" $(TerminalType)$(VMACMode).fst -nogui
#echo __________________ move files to out directory __________________
# rename the .p7s file we just created
move $(OutDir)\$(ProjectName).out.p7s $(OutDir)\$(ProjectName).p7s
!if "$(VMACMode)"=="Multi"
copy $(ResDir)\imm.ini $(OutDir)\imm.ini
copy $(ResDir)\$(ProjectName).INS $(OutDir)\$(ProjectName).INS
copy $(ResDir)\$(ProjectName).res $(OutDir)\$(ProjectName).res
!endif
#echo *****************************************************************
Now let's define how we will do the linking:
# Link object files
$(OutDir)\$(ProjectName).out : $(AppObjects)
$(EVOSDK)\bin\vrxcc $(COptions) $(AppObjects) $(Libs) -o $(OutDir)\$(ProjectName).out
...and build the .res file...
#This will actually build the .res file. (We only said we were going to do it above)
!if "$(VMACMode)"=="Multi"
# compile resource file
$(ResDir)\$(ProjectName).res : $(ResDir)\$(ProjectName).rck
# SET INCLUDE=$(INCLUDE);$(EVOVMAC)\include;$(EVOVMAC)\template --> I put this into my include path for the project, instead
$(EVOTOOLS)rck2 -S$(ResDir)\$(ProjectName) -O$(ResDir)\$(ProjectName) -M
!endif
and now we can actually run the compilation:
# Compile modules --> -c = compile only, -o = output file name, -e"-" => -e redirect error output from sub-tools to... "-" to stdout. (These are all then redirected via pipe | )
# For more details, see Verix_eVo_volume 3, page 59
$(ObjDir)\$(ProjectName).o : $(SrcDir)\$(ProjectName).c
!IF !EXISTS($(OutDir))
!mkdir $(OutDir)
!ENDIF
-$(EVOSDK)\bin\vrxcc -c $(COptions) $(Includes) -o $(ObjDir)\$(ProjectName).o $(SrcDir)\$(ProjectName).c -e"-" | "$(EVOTOOLS)fmterrorARM.exe"
$(ObjDir)\Base.o : $(SrcDir)\Base.c
$(EVOSDK)\bin\vrxcc -c $(COptions) $(Includes) -o $(ObjDir)\base.o $(SrcDir)\Base.c -e"-" | "$(EVOTOOLS)fmterrorARM.exe"
$(ObjDir)\UI.o : $(SrcDir)\UI.c
$(EVOSDK)\bin\vrxcc -c $(COptions) $(Includes) -o $(ObjDir)\UI.o $(SrcDir)\UI.c -e"-" | "$(EVOTOOLS)fmterrorARM.exe"
$(ObjDir)\Comm.o : $(SrcDir)\Comm.c
$(EVOSDK)\bin\vrxcc -c $(COptions) $(Includes) -o $(ObjDir)\Comm.o $(SrcDir)\Comm.c -e"-" | "$(EVOTOOLS)fmterrorARM.exe"
And that's the last line--there is no other fanfare or what-have-you.
I would like to point something out that you may have noticed, but threw me for a loop when I was getting started on all of this: we kinda' do everything backwards. If I were telling a person how to build the project, I would start by telling them how to compile everything to it's .o file first, but that's the last step in a make file. Next, I would tell a person how to do the linking, but that's the 2nd to last step, and so on.
If you still need more info, visit the link I included--it's way more authoritative than I am and includes a lot of details I probably missed. Hopefully this is enough to get you going, though.

Related

Creating target from searched directories

I want to create separate executables for each directory named "test" in my project. Test directory has structure like this:
test.mk
test (dir)
|__test.mk
|__testRun.c
|__testRun.h
test.mk contains dependencies for specific test, testRun.c is the test itself.
So hierarchy looks like this:
ROOT
|__Makefile
|__Module1 (dir)
|__some files
|__test (dir)
|__Module2 (dir)
|__some files
|__test (dir)
|__Module3 (dir)
|__some files
|__test (dir)
|__outdir (dir)
|__test1 (exec)
|__test2 (exec)
|__test3 (exec)
I want to run single Makefile in root parent directory. I want it to search for all test directories and create test executables in outdirectory. So far I have this:
Makefile
CFLAGS = -I$(DIRTEST) -I$(DIRTEST)/..
OUTDIR= ./outdirectory
DIRTEST = $(shell find -type d -not -path "$(OUTDIR)/*" -name "test" -prune )
I have no idea how to create rule that creates target executable from sources and headers from separate directories. I was looking for solution for similar problem, but no luck so far.
Note: I do not want to use recursive make. test.mk looks for example like this:
SRCTEST = module1/test/testRun.c \
module1/module1.c
CFLAGS += -Imodule1
You can use bash scripts files for building variables, in case if you are avoiding a recursive build.
cat module1/test/test.sh
export SRCTEST="module1/test/testRun.c
module1/module1.c"
export CFLAGS="$CFLAGS -Imodule1"
cat module2/test/test.sh
export SRCTEST="module2/test/testRun.c
module2/module2.c"
export CFLAGS="$CFLAGS -Imodule2"
Then your Makefile could looks like:
test1:
source module1/test/test.sh && gcc -o $# $$CFLAGS $$SRCTEST
test2:
source module2/test/test.sh && gcc -o $# $$CFLAGS $$SRCTEST
Also you can do something with include instruction. Redefinition could be avoided by checking the build target, but this is not a good way.
Your examples are not clear enough for us to answer.
For one thing, tt's not clear how the name of the test executable is related to the name of the module. Is it really the case that the modules end with a number and the generated test program should also end with that same number (Module1 -> test1)? Or is there some other relationship? There doesn't appear to be any variable containing a test name in the test.mk file so how is the test name computed?.
Second, it will make your life very difficult if you redefine the same variables in every test.mk file. There is no "scoping" in make that will allow you to say "this instance of CFLAGS is used only for this included makefile". Each time you include a different test.mk file it will overwrite the previous settings.
It CAN be done: you'll need to use a combination of define variables to hold rule definitions, then eval to evaluate the rules.
Let's suppose that you added a new variable to test.mk which defined the test name, and you qualified your variables with this name as well; then your life is much easier:
Module1/test/test.mk would contain:
TESTNAME = test1
test1_SRCTEST = module1/test/testRun.c \
module1/module1.c
test1_CFLAGS = -Imodule1
Now in your main makefile you would create a variable holding the rule you wanted to define:
define MAKETEST
include $T
$$(OUTDIR)/$$(TESTNAME): $$(OUTDIR)/% : $$($$(TESTNAME)_SRCTEST)
$$(CC) $$(CPPFLAGS) $$(CFLAGS) $$($$*_CFLAGS) -o $$# $$^
endef
$(foreach T,$(DIRTEST),$(eval $(MAKETEST)))
Note, this is untested.

Gnu-Make fails to include a makefile

From the docs:
The include directive tells make to suspend reading the current
makefile and read one or more other makefiles before continuing. The
directive is a line in the makefile that looks like this:
include FILENAMES...
FILENAMES can contain shell file name patterns.
Now, given a Makefile:
# we define 'include' from the command-line.
ifdef include
# We create the included Makefile
$(shell echo 'all : ;' >makefile.include)
# And we include it.
# The docs say: "FILENAMES can contain shell file name patterns."
include *.include
else
endif
Running, we get:
$ rm -rf makefile.include && make include=1
makefile:6: *.include: No such file or directory
So, what happened here? We clearly had:
Created a Makefile to be included, in:
$(shell echo 'all : ;' >makefile.include)
And later included this makefile, given that we can using "shell file name patterns", as quoted above from the documentation - and thus, we have in the makefile:
include *.include
So, why did Gnu-Make failed to find this newly-created makefile?
The problem you are facing is not of inclusion, but of order of execution.
make is not a procedural language, but instead a declarative one, so order-of-execution sometimes gets a bit tricky.
In your specific case, make will parse the entire Makefile in the first pass, including the include statements, resulting in an erroneous Makefile, since there is no makefile.include yet.
It will then execute the shell command to create the makefile.include (but again it is too late: inclusion would have happened before).
A second run of make will then correctly include the makefile.include.
Note:
The same is true for both directly using include *.include and include $(wildcard *.include) but only the former will result in an error (since the latter will expand the *.include to an empty set which will then (not) be included, whereas the former will try to include the literal *.include - similar to a stray cat *.nonexistent on the shell).

(vxworks) In the binary produced using this linker script, why doesn't the first address encountered start at the text segment start address?

I have a project I'm working on in vxWorks, constructing a vxsim binary for testing. There's three stages to the link process; the relevant portions of the makefile look roughly like the following:
partialImage.o: ${SYSTEM_OBJS} ${OBJS} version.o
ldsparc ${appropriate LDFLAGS go here} ${^} -o ${#}
# Don't ask me why they did it this way; it seems redundant to re-use
# all the other objects as well as partialImage.o, but I'm also not extremely
# versed in what's necessary for munch.tcl to do its thing.
ctdt.o: partialImage.o ${SYSTEM_OBJS} ${OBJS} version.o
${VXSIMNM} ${^} | tclsh ${path to munch.tcl} > ${#:%.o=%.c}
ccsparc ${appropriate CFLAGS go here} ${#:%.o=%.c} -o ${#}
${FINAL_IMAGE}: ${a list of dependencies here}
ldsparc -N -e _sysInit -Ttext 60010000 \
${appropriately ordered list of objects} \
-defsym _VX_DATA_ALIGN=16 \
-T link.RAM \
-o ${#}
If more information is necessary (flags & the like) let me know. I'm not at that computer at the moment, but in about an hour I'll update this question with further details if no answer is forthcoming by that time.
The following is a rough sketch of the linker script. If you have access to vxWorks 6.x, it's just the default 'link.RAM' script:
START(_sysInit)
SECTIONS {
.text {
wrs_kernel_text_start = .;
/* A few other variable declarations and inclusions from various other segments */
. = ALIGN(16);
}
. = ALIGN(16);
/* The rest of the linker script */
}
Take note of the fact that wrs_kernel_text_start occurs at the beginning of the text segment before anything is included and before any ALIGN statements.
In other vxWorks projects I've done, wrs_kernel_text_start = 0x60010000; however, on this particular project it's some other address roughly on par with 0x6025XXXX. You're not reading that wrong, the address is 1 order of magnitude higher than the address I expect -- that is, it isn't 0x60025XXX. _sysInit starts right at 0x60010000 as I expect.
I was going to delete the question, but I suppose someone out there might get some value from the answer. The makefile ACTUALLY looked like this:
outfile: ${SYSTEM_OBJS} ${OBJS} version.o link.RAM
ldsparc ${appropriate LDFLAGS go here} ${^} -o ${#}
(...)
Note that the linker script was in the dependency list, and I was including it with ${^} as one of the input files. When I removed the linker script from the dependency list, everything looks normal now.

How do I run a C program from VIM?

Is there a way to compile and run a C program from VIM without typing its filename ?
:!gcc -o somename % && ./somename
When using :!, % will be substituted by the name of the currently opened file.
When your project becomes larger, you can also write a makefile and compile the current project with :make, if there are any errors, vim will jump to them automatically.
Use the following mapping code in your .vimrc file for compiling and running a c programming file.
map <F8> : !gcc % && ./a.out <CR>
F8 key is for run the mapping. "%" is to take the current file name.
Or, if you want to save the current file before compiling it, use
map <F8> :w <CR> :!gcc % && ./a.out <CR>
Or more ideally, if you want to use the file basename not the default 'a.out' as the executable file name, use the following:
map <F8> :w <CR> :!gcc % -o %< && ./%< <CR>
In the above command, "<" after "%" removes extension and dot (foo.c => foo), so "%<" is the file basename.
You can find this and similar infos in cmdline.txt. Command in vim:help: cmdline.txt. You can also find specific details about the use of "%" by using :help filename-modifiersin vim.
TL;DR No Makefile is required, tweaking &makeprg is also completely useless, and yet :make %< is enough to compile from Vim.
Long answer:
I duplicate an answer I gave in a closed "duplicate question".
Considering we are using vim, and not vi, :make is the way to go.
On Linux-like (it also applies to cygwin, but not to mingw on windows -- in mingw case, see the other answers that alter &makeprg, leave it alone otherwise) systems where gnumake is installed, if you don't have a Makefile in your project, and if your project is made of only one file, just type :make %<. It will be enough (you can play with $CXXFLAGS, $CFLAGS, $LDFLAGS (for -Llib/path options) and $LDLIBS (for -llibname options) to tune the compilation options). Then to run the program, type :!./%<, or with latter versions of vim, run :terminal ./%<.
If your project is made of several files, then you'll need a Makefile to take advantage of :make.
If you manage your project with CMake, and if you compile your project in a directory (or several -> debug, release, ...) outside the sources tree, then the integration will require a plugin. AFAIK, I'm the only one to propose such a plugin: BuildToolsWrapper integrates the management of CMake (choice of the build directory, possibility to chose between the debug, or release, or whatever build directory). It has to be coupled with one of the local_vimrc plugin.
In all cases, calling directly the compiler from within (or outside) Vim with :!g++ -o %< % or whatever is what we used to do 15 years ago on vi. Vim has a wonderful feature: it can integrate (yes, like in IDE) the compiler. See :h quickfix. Navigating between errors directly from the editor is much easier than extracting one error line with our eyes, typing back the line number into the editor, going back to the shell to see what exactly was rejected, ... It may be enough in C, but In C++ when we are "trying to call an overload that doesn't exist", we can't work this way (switching back and forth between the editor and the shell).
Finally, if you want to compile on a single keystroke those mono-file projects, you can add in your .vimrc:
nnoremap <silent> <f7> :make %<<cr>
If you want to adapt automatically the compilation command depending of the kind of project mono-file pet project, or real world multi-file project, well, more wiring is needed, and this is what BTW does -- it reads various options to know what to do.
Last note: &makeprg is best left alone, at least not set to g++/gcc/clang/clang++/gfortran/... Because, every time you change your language, you'll have to change it (unless you use :setlocal). With the solution I recommend, if I want to use clang++ instead of g++, all I have to do is to set: :let $CXX='clang++' (or $CC in C), and then call :make %<. I can even define :let $CXXFLAGS='-std=c++11' to compile in C++11 -- the same variable will be used to turn warnings on, to use a sanitizer, etc.
It's 2018 now, vim 8 has released for 2 years and shipped with all the Linux distributions and Mac OS X. But a lot of vim tutorials are still teaching people something ten years ago.
You can compile your C++/Java programs in vim as convenience as Sublime Text or NotePad++ with some dedicated plugins for Vim 8 or NeoVim.
For example, the AsyncRun plugin will allow you run shell commands in background and read output from quickfix window in realtime.
See the screen capture.
Just like compiling programs in IDEs, the compilation errors will be matched by errorformat and be highlighted and become selectable. You can navigate errors in the quickfix window or continue editing while compiling.
Quick setup
Copy & paste the lines below to your vimrc:
Plug 'skywind3000/asyncrun.vim'
" open quickfix window automatically when AsyncRun is executed
" set the quickfix window 6 lines height.
let g:asyncrun_open = 6
" ring the bell to notify you job finished
let g:asyncrun_bell = 1
" F10 to toggle quickfix window
nnoremap <F10> :call asyncrun#quickfix_toggle(6)<cr>
When you input “:AsyncRun echo hello ” in the command line:
see the capture here
You will see the realtime command output in the open quickfix window.
Compile and run a single file
Compiling a single file with AsyncRun is much simpler than Sublime Text’s build system. We can setup F9 for this:
noremap <silent> <F9> :AsyncRun gcc -Wall -O2 "$(VIM_FILEPATH)" -o "$(VIM_FILEDIR)/$(VIM_FILENOEXT)" <cr>
The macros in $(..) form will be expanded as the real file name or directory, and then we will have F5 to run the executable:
noremap <silent> <F5> :AsyncRun -raw -cwd=$(VIM_FILEDIR) "$(VIM_FILEDIR)/$(VIM_FILENOEXT)" <cr>
The double quotation mark is used to handle path names containing spaces. The option -cwd=$(VIM_FILEDIR) means running the file in the file's directory. The absolute path name $(VIM_FILEDIR)/$(VIM_FILENOEXT) is used because linux needs a ./ prefix to running executables in current directory, but windows doesn't . Using the absolute path name of the binary file can handle this crossing platform issue.
Another option -raw means the output will not be matched by vim's errorformat, and will be displayed in quickfix as what it is. Now you can compile your file with F9, check the compilation errors in quickfix window and press F5 to run the binary.
Build C/C++ Projects
No matter what build tool you are using, make or cmake, project building means acting to a group of files. It requires locating the project root directory. AsyncRun uses a simple method called root markers to identify the project root. The Project Root is identified as the nearest ancestor directory of the current file which contains one of these directories or files:
let g:asyncrun_rootmarks = ['.svn', '.git', '.root', '_darcs']
If none of the parent directories contains these root markers, the directory of the current file is used as the project root. This enables us to use either <root> or $(VIM_ROOT) to represent the project root. and F7 can be setup to build the current project:
noremap <silent> <F7> :AsyncRun -cwd=<root> make <cr>
What if your current project is not in any git or subversion repository ? How to find out where is my project root ? The solution is very simple, just put an empty .root file in your project root, it will be located easily.
Let’s move on, setup F8 to run the current project:
noremap <silent> <F8> :AsyncRun -cwd=<root> -raw make run <cr>
The project will run in its root directory. Of course, you need define the run rule in your own makefile. then remap F6 to test:
noremap <silent> <F6> :AsyncRun -cwd=<root> -raw make test <cr>
If you are using cmake, F4 can be map to update your Makefile:
nnoremap <silent> <F4> :AsyncRun -cwd=<root> cmake . <cr>
Due to the implementation of c runtime, if the process is running is a non-tty environment, all the data in stdout will be buffered until process exits. So, there must be a fflush(stdout) after your printf statement if you want to see the real-time output. or you can close the stdout buffer at the beginning by
setbuf(stdout, NULL);
At the mean time, if you are writing C++ code, a std::endl can be appended to the end of std::cout. It can force flush the stdout buffer. If you are developing on windows, AsyncRun can open a new cmd window for the child process:
nnoremap <silent> <F5> :AsyncRun -cwd=$(VIM_FILEDIR) -mode=4 "$(VIM_FILEDIR)/$(VIM_FILENOEXT)" <cr>
nnoremap <silent> <F8> :AsyncRun -cwd=<root> -mode=4 make run <cr>
Using the option -mode=4 on windows will open a new prompt window to run the command, just like running command line programs in Visual Studio. Finally, we have these key mappings below:
F4: update Makefile with cmake.
F5: run the single file
F6: run project test
F7: build project
F8: run project
F9: compile the single file
F10: toggle quickfix window
It is more like build system in NotePad++ and GEdit. If you are using cmake heavily, you can write a simple shell script located in ~/.vim/script/build.sh to combine F4 and F7 together: it will update Makefile if CMakeList.txt has been changed, then exectute make.
Advanced usage
You can also define shell scripts in your dotfiles repository and execute the script with F3:
nnoremap <F3> :AsyncRun -cwd=<root> sh /path/to/your/dotfiles/script/build_advanced.sh <cr>
The following shell environment variables are defined by AsyncRun:
$VIM_FILEPATH - File name of current buffer with full path
$VIM_FILENAME - File name of current buffer without path
$VIM_FILEDIR - Full path of current buffer without the file name
$VIM_FILEEXT - File extension of current buffer
$VIM_FILENOEXT - File name of current buffer without path and extension
$VIM_CWD - Current directory
$VIM_RELDIR - File path relativize to current directory
$VIM_RELNAME - File name relativize to current directory
$VIM_ROOT - Project root directory
$VIM_CWORD - Current word under cursor
$VIM_CFILE - Current filename under cursor
$VIM_GUI - Is running under gui ?
$VIM_VERSION - Value of v:version
$VIM_COLUMNS - How many columns in vim's screen
$VIM_LINES - How many lines in vim's screen
$VIM_SVRNAME - Value of v:servername for +clientserver usage
All the above environment variables can be used in your build_advanced.sh. Using the external shell script file can do more complex work then a single command.
Grep symbols
Sometimes, If you don't have a well setup environment in you remote linux box, grep is the most cheap way to search symbol definition and references among sources. Now we will have F2 to search keyword under cursor:
if has('win32') || has('win64')
noremap <F2> :AsyncRun! -cwd=<root> grep -n -s -R <C-R><C-W> --include='*.h' --include='*.c*' '<root>' <cr>
else
noremap <F2> :AsyncRun! -cwd=<root> findstr /n /s /C:"<C-R><C-W>" "\%CD\%\*.h" "\%CD\%\*.c*" <cr>
endif
The above script will run grep or findstr in your project root directory, and find symbols in only .c, .cpp and .h files. Now we move around the cursor and press F2, the symbol references in current project will be displayed in the quickfix window immediately.
This simple keymap is enough for most time. And you can improve this script to support more file types or other grep tools in your vimrc .
That’s the practical way to build/run C/C++ projects in Vim 8 or NeoVim. Just like Sublime Text’s build system and NotePad++’s NppExec.
No more outdated vim tutorials again, try something new.
since most of the time you would use a Makefile, in addition to the given answers, I also like to see my results in a "cleared" screen:
map <F10> :w<CR> :!clear; make<CR> :!./%<<CR>
:w<CR> saves the file
:!clear; make<CR> clears the screen and runs make
:!./%<<CR> runs a program (%) without the extension (<)
Add this line in your vimrc file
nnoremap <silent> <F8> :!clear;gcc % -o % && ./%<CR>
Now you only have to press f8 key to compile and run your c program.
Just thought I would add this to these answers here. As has been mentioned, you can use the :make command in vim. What has not been mentioned yet, is that :make can invoke other programs, other than make.
:set makeprg=gcc\ %
Will cause :make to execute gcc with the % symbol replaced by the current file name.
You can then get fancy and do
:set makeprg=gcc\ %\ &&\ ./a.out
and simply typing :make will compile and execute your program. You can do this for other languages as well of course.
:set makeprg=cabal\ repl
:set makeprg=python\ %
After doing some research (including this very page), I made my mind to add this shortcut:
map <F9> :w<CR> :!gcc % -o %<.x -Wall -Wextra 2>errors.err; cat errors.err<CR>
You can also include -ansi -pedantic-errors if you will.
The errors.err file will help you with vi quickfix.
I looked through all of these solutions and I found that they didn't work (as far as I could tell) for the case of editing a file in a different directory -- I wrote some vimscript that does this in a kinda clunky way, but hopefully someone can find this useful:
let mycommand = ':!gcc % -o %< && echo "%<" && [ $(pwd) == "." ] && %< || ./%< '
nnoremap <silent> <F8> :execute mycommand <CR>
or if the commands above work for you in multiple directories feel free to just ignore this.
It may be worth adding that SingleCompile plugin offers that facility for C and other languages as stated by the author:
SingleCompile is a Vim plugin aimed at making it more convenient to
compile or run a single source file without leaving Vim. Consider this
situation: you have just written a small C source file for a tiny
test, but you have to write a Makefile to compile it, or exit Vim to
compile it, or compile it using "!gcc" without quickfix feature
because Vim's make command only use the "make" command? This plugin
will help you out.
Suggested mappings for F9 and F10:
nmap <F9> :SCCompile<cr>
nmap <F10> :SCCompileRun<cr>
I have created command to Run my c & cpp codes
:command Runcpp !clear;g++ % -o %:r && ./%:r<CR>
:command Runc !clear;gcc % -o %:r && ./%:r<CR>
Put above code in .vimrc file and run you code using command Runcpp & Runc
you Can easily compile and run your program from vim directly just go to normal mode and type
:!gcc yourProgramName.c
and then just simply write the following to run the program
:!gcc % | ./a.out
Add these three lines to your .vimrc file
au FileType c set makeprg=gcc\ %
au FileType cpp set makeprg=g++\ %
map <F7>:make && ./a.out<CR>
You can compile and run your program by pressing the F7 button.
I have the following in my vimrc:
autocmd filetype c nnoremap <F9> :w<CR> :!clear<CR> :!gcc % -o %< && %<<CR>
This will allow you to Compile/Run C with <F9> and clear console
You can also do the following:
autocmd filetype c nnoremap <F8> :w<CR> :!clear<CR> :!make && ./%<<CR>
This will allow you to Compile/Run C using Makefile with <F8> and clear console

How can I get my C code to automatically print out its Git version hash?

Is there an easy way to write C code that can access its Git version hash?
I wrote software in C to collect scientific data in a laboratory setting. My code records the data it collects in a .yaml file for later analysis. My experiments change from day-to-day and I often have to modify the code. To keep track of revisions, I use a git repository.
I would like to be able to include the Git revision hash as a comment in my .yaml data files. That way, I could look at the .yaml file and know exactly what code was used to generate the data shown in that file. Is there an easy way to do this automatically?
If you are using a make-based build, you can put this in the Makefile:
GIT_VERSION := "$(shell git describe --abbrev=4 --dirty --always --tags)"
(See man git describe for what the switches do)
then add this to your CFLAGS:
-DVERSION=\"$(GIT_VERSION)\"
Then you can just reference the version directly in the program as though it was a #define:
printf("Version: %s\n", VERSION);
By default this just prints an abbreviated git commit id, but optionally you can tag particular releases with something like:
git tag -a v1.1 -m "Release v1.1"
then it will print out:
Version: v1.1-2-g766d
which means, 2 commits past v1.1, with a git commit id beginning with "766d".
If there are uncommitted changes in your tree, it will append "-dirty".
There is no dependency scanning so you have to do an explicit make clean to force the version to be updated. This can be solved however.
The advantages are that it is simple and doesn't require any extra build dependencies like perl or awk. I have used this approach with GNU automake and with Android NDK builds.
In my program, I hold the git version number and the date of the build in a separate file, called version.c, which looks like this:
#include "version.h"
const char * build_date = "2009-11-10 11:09";
const char * build_git_sha = "6b54ea36e92d4907aba8b3fade7f2d58a921b6cd";
There is also a header file, which looks like this:
#ifndef VERSION_H
#define VERSION_H
extern const char * build_date; /* 2009-11-10 11:09 */
extern const char * build_git_sha; /* 6b54ea36e92d4907aba8b3fade7f2d58a921b6cd */
#endif /* VERSION_H */
Both the header file and the C file are generated by a Perl script which looks like this:
my $git_sha = `git rev-parse HEAD`;
$git_sha =~ s/\s+//g;
# This contains all the build variables.
my %build;
$build{date} = make_date_time ();
$build{git_sha} = $git_sha;
hash_to_c_file ("version.c", \%build, "build_");
Here hash_to_c_file does all the work of creating version.c and version.h and make_date_time makes a string as shown.
In the main program, I have a routine
#include "version.h"
// The name of this program.
const char * program_name = "magikruiser";
// The version of this program.
const char * version = "0.010";
/* Print an ID stamp for the program. */
static void _program_id_stamp (FILE * output)
{
fprintf (output, "%s / %s / %s / %s\n",
program_name, version,
build_date, build_git_sha);
}
I'm not that knowledgeable about git, so I'd welcome comments if there is a better way to do this.
I ended up using something very similar to #Kinopiko's answer, but I used awk instead of perl. This is useful if your stuck on windows machines which have awk installed by nature of mingw, but not perl. Here's how it works.
My makefile has a line in it that invokes git, date, and awk to create a c file:
$(MyLibs)/version.c: FORCE
$(GIT) rev-parse HEAD | awk ' BEGIN {print "#include \"version.h\""} {print "const char * build_git_sha = \"" $$0"\";"} END {}' > $(MyLibs)/version.c
date | awk 'BEGIN {} {print "const char * build_git_time = \""$$0"\";"} END {} ' >> $(MyLibs)/version.c
Everytime I compile my code, the awk command generates a version.c file that looks like this:
/* version.c */
#include "version.h"
const char * build_git_sha = "ac5bffc90f0034df9e091a7b3aa12d150df26a0e";
const char * build_git_time = "Thu Dec 3 18:03:58 EST 2009";
I have a static version.h file that looks like this:
/*version.h*/
#ifndef VERSION_H_
#define VERSION_H_
extern const char * build_git_time;
extern const char * build_git_sha;
#endif /* VERSION_H_ */
The rest of my code can now access the build-time and the git hash by simply including the version.h header. To wrap it all up, I tell git to ignore version.c by adding a line to my .gitignore file. This way git isn't constantly giving me merge conflicts. Hope this helps!
Your program can shell out to git describe, either at runtime or as part of the build process.
There are two things that you can do:
You can make Git to embed some version information in the file for you.
The simpler way is to use ident attribute, which means putting (for example)
*.yaml ident
in .gitattributes file, and $Id$ in the appropriate place. It would be automatically expanded to SHA-1 identifier of the contents of the file (blob id): this is NOT file version, or the last commit.
Git does support $Id$ keyword in this way to avoid touching files which were not changed during branch switching, rewinding branch etc. If you really want Git to put commit (version) identifier or description in the file, you can (ab)use filter attribute, using clean/ smudge filter to expand some keyword (e.g. $Revision$) on checkout, and clean it up for commit.
You can make build process to do that for you, like Linux kernel or Git itself does.
Take a look at GIT-VERSION-GEN script and its use in Git Makefile, or for example how this Makefile embeds version information during generation / configuration of gitweb/gitweb.cgi file.
GIT-VERSION-GEN uses git describe to generate version description. It needs to work better that you tag (using signed / annotated tags) releases / milestones of your project.
When I need to do this, I use a tag, like RELEASE_1_23. I can decide what the tag can be without knowing the SHA-1. I commit then tag. You can store that tag in your program anyway that you like.
Based on the answer by njd27, I'm using the a version with dependency scanning, in combination with a version.h file with default values for when the code is built in a different way. All files that include version.h will be rebuilt.
It also includes the revision date as a separate define.
# Get git commit version and date
GIT_VERSION := $(shell git --no-pager describe --tags --always --dirty)
GIT_DATE := $(firstword $(shell git --no-pager show --date=short --format="%ad" --name-only))
# recompile version.h dependants when GIT_VERSION changes, uses temporary file version~
.PHONY: force
version~: force
#echo '$(GIT_VERSION) $(GIT_DATE)' | cmp -s - $# || echo '$(GIT_VERSION) $(GIT_DATE)' > $#
version.h: version~
#touch $#
#echo Git version $(GIT_VERSION) $(GIT_DATE)
I also use git to track changes in my scientific code. i didn't want to use an external program because it limits portability of the code (if someone would want to make changes on MSVS for example).
my solution was to use only the main branch for the calculations and make it output the build time using preprocessor macros __DATE__ and __TIME__. that way i can check it with git log and see which version i'm using. ref: http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
another elegant way to solve the problem is to include git log into the executable.
make an object file out of git log and include it into the code. this time the only external program you use is objcopy but there is less coding. ref: http://www.linuxjournal.com/content/embedding-file-executable-aka-hello-world-version-5967 and Embed data in a C++ program
What you need to do is to generate a header file (eg using echo from cmd line) something like this:
#define GIT_HASH \
"098709a0b098c098d0e"
To generate it use something like this:
echo #define GIT_HASH \ > file.h
echo " > file.h
echo git status <whatever cmd to get the hash> > file.h
echo " > file.h
Might need to play with the quotes and backslashes a bit to get it to compile, but you get the idea.
This is a solution for CMake projects that works for Windows and Linux, without the need for any other programs (e.g. script languages) to be installed.
The git hash is written to a .h file by a script, which is a bash script when compiling on Linux or a Windows batch script when compiling on Windows. An if-clause in CMakeLists.txt is used to execute the script corresponding to the platform the code is compiled on.
Save the following 2 scripts in the same directory as CMakeLists.txt:
get_git_hash.sh:
#!/bin/bash
hash=$(git describe --dirty --always --tags)
echo "#ifndef GITHASH_H" > include/my_project/githash.h
echo "#define GITHASH_H" >> include/my_project/githash.h
echo "const std::string kGitHash = \"$hash\";" >> include/my_project/githash.h
echo "#endif // GITHASH_H" >> include/my_project/githash.h
get_git_hash.cmd:
#echo off
FOR /F "tokens=* USEBACKQ" %%F IN (`git describe --dirty --always --tags`) DO (
SET var=%%F
)
ECHO #ifndef GITHASH_H > include/my_project/githash.h
ECHO #define GITHASH_H >> include/my_project/githash.h
ECHO const std::string kGitHash = "%var%"; >> include/my_project/githash.h
ECHO #endif // GITHASH_H >> include/my_project/githash.h
In CMakeLists.txt add the following lines at the beginning to define the custom target "write_git_hash"
if(WIN32)
add_custom_target( write_git_hash
get_git_hash.cmd
COMMENT "Call batch script for writing git hash"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
else()
add_custom_target( write_git_hash
./get_git_hash.sh
COMMENT "Call shell script for writing git hash"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
endif()
Make sure to add the "include" folder to your project
project(my_project)
include_directories(include)
After you define the executable, add "write_git_hash" as a dependency
add_executable(my_project src/my_cpp_file.cpp)
add_dependencies(my_project write_git_hash)
This will trigger the generation of the githash.h when building the project.
Include the githash.h file in your C++ file with #include <my_project/githash.h>.
You should now be able to print the git hash to the terminal with
std::cout << "Software version: " << kGitHash << std::endl;
or do with it whatever you like.
Yet another variation based on Makefile and shell
GIT_COMMIT_FILE=git_commit_filename.h
$(GIT_COMMIT_FILE): phony
$(eval GIT_COMMIT_SHA=$(shell git describe --abbrev=6 --always 2>/dev/null || echo 'Error'))
#echo SHA=$(GIT_COMMIT_SHA)
echo -n "static const char *GIT_COMMIT_SHA = \"$(GIT_COMMIT_SHA)\";" > $(GIT_COMMIT_FILE)
File git_commit_filename.h will end up with a single line containing
static const char *GIT_COMMIT_SHA="";
From https://gist.github.com/larytet/898ec8814dd6b3ceee65532a9916d406
You can see how I did it for memcached in the original commit.
Basically, tag occasionally, and make sure the thing you deliver comes from make dist or similar.

Resources