페이지

2020년 6월 20일 토요일

Local Environment Setup

* If you are still willing to set up your environment for Go programming language, you need the following software available on your computer:
- A text editor
- Go compiler

The source code written in source file is the human readable source for your program. It needs to be compiled and turned into machine language so that your CPU can actually execute the program as per the instructions given. The Go programming language compiler compiles the source code into its final executable program.

Go distribution comes as a binary installable for FreeBSD(release 8 and above), Linux, Mac OS X(Snow Leopard and above), and Windows operating systems with 32-bit(386) and 64-bit(amd64) x86 processor architectures.
The following section explains how to install Go binary distribution on various OS.


- Download Go Archive
Download the latest version of Go installable archive file from Go Downloads. The following version is used in this tutorial: go1.4.windows-and64.msi.

it is copied it into C:\>go folder.

Installation on UNIX/Linux/Mac OS X, and FreeBSD
Extract the download archive into the folder /usr/local, createing a Go tree in
/usr/local/go. For example:
tar -C /user/local -xzf go1.4.linux-amd64.tar.gz
Add /usr/local/go/bin to the PATH environment variable.


export PATH=$PATH:/usr/local/go/bin






 





2020년 6월 19일 금요일

Try it Option Online

* You really do not need to set up your own environment to start learning Go programming language. Reason is very simple, we already have set up Go Programming environment online, so that you can compile and execute all the available examples online at the same time when you are doing your theory work.

* This gives you confidence in what you are reading and to check the result with different options. Feel free to modify any example and execute it online.

Try the following example using the Try it option available at the top right corner of the following sample code displayed on our website:

package main

import "fmt"

func main() {fmt.Println("Hello, World!")
}

For most of the examples given in this tutorial, you will find a Try it option.


Compiling Java in the Shell(Optional)

 * Java programs get compiled into object code for an imaginary CPU called the "Java Virtual Machine"(JVM). Consequently, you can't execute compiled Java code directly, You must run program that simulates a JVM and let that simulated computer execute the Java code.

* That may seem a little convoluted, but the JVM simulator is easier to write than a "true" compiler. Consequently, JVM simulators can be built into other programs (such as web browsers), allowing Java code compiled on one machine to be executed on almost any other machine. By contrast, a true native-code compiler (e.g., g++) produces executable that can only be run on a single kind of computer.

* The command to compile Java code is "javac" ("c" for compiler) and the command to execute compiled java code is "java". So a typical sequence to compile and execute a single-file Java program would b

javac -g MyProgram.java
java MyhProgram


* Unlike most programming languages, Java includes some important restrictions on the file names used to store source code.

Java source code is stored in files ending with the extension ".java".

Each Java source code file must contain exactly one public class declaration.

* The base name of the file (the part before the extension) must be the same (including upper/lower case characters) as the name of the public class it contains.

So the command

javac -g MyProgram.java

* ocmpiles a file that must contain the code:

public 
class MyProgram ...

The output of this compilatioin will be a file named MyProgram.class ( and possibly some other .class files as well).

* If we have a program that consists of multiple files, we can simply compile each file in turn:

javac -g MyProgram.java
javac -g MyADT.java

but this might not be necessary. If one Java file imports another, then the imported file will be automatically compiled if no .class file for it exists.















Understanding the Error Message

* Cascading one thing to keep in mind i that errors, especially errors in declarations, can cascade, with one "misunderstanding" by the compiler leading to a whole host of later messages. For example, if you meant to write

string s;

but instead wrote

strng s;

* You will certainly get an error message for the unknown symbol strng. However, there's also the factor that the compiler really doesn't know what types any symbol of unknown type is supposed to be an int. So every time you subsequently uses in a "string-like" mananer, e.g.,

s = s + "abcdef";

or

sting t = s.substring(k,m);

* The compiler will probably issue further complaints. Sometimes, therefore, it's best to stop after fixing a few declaration errors and recompile to see how many of the other messages need to be taken seriously.

* Backtracking A compiler can only report where it detected a problem. Where you actually committed a mistake may be someplace entirely different.

The vast majority of error messages that C++ programmers will see are


* syntax eror (missing brackets, semi-colons, etc.)
undeclared symbols
undefined symbols
type errors (usually "cannot find a matching function" complaints)

const errors

Let's look at these from the point of view of the compiler.






Capturing Compiler Output

* There are other ways to capture the output of a compiler (or of any running program). You can run the compiler within the emacs editor, which then gives you a simple command to move from error message to error message, automatically bringing up the source code file on the line cited in the error message. This works with both the UNIX and the MS Windows ports of emacs, and is the technique I use myself. Vim, the "vi improved" editor will do the same.

* Finally, in UNIX there is a command clalled "script" that causes all output to your screen to be captured in a file.
Just say

script log.txt

and all output to your screen will be copied into log.txt until you say

exit

* script output can be kind of ugly, because it includes all the control characters that you type or that your programs use to control formatting on the screen, but it's still useful.


Pipes and redirection

* We introduced pipes and redirection earlier. The complicating factor here is that what you want to pipe or redirect is not the standard output stream, but the standard error stream. So, for example, doing something like

g++ myprogram.cpp >  compilation.log

or 

g++ mayprogram.cpp | more


* It won't work, because these commands are only redirecting the standard output stream. The error message will continue to blow on by.

How you pipe or redirect the standard error stream depends on the shell you are running:

Unix, running C-shell or TC-shell

* The > and | symbols can be modified to affect the standard error stream by appending a '&' character. So these commands do work:

g++ myprogram.cpp >& compilation.log
g++ myprogram.cpp |& more


* A useful program in this regard is tee, which copies its standard input both into the standard output and into a named file:

g++ myprogram.cpp |& tee compilation.log

Linux/CygWin , running bash

* The sequence "2>&1" in a command means "force the standard error to go wherever the standard output is going".. So we can do any of the following:

g++ myprogram.cpp 2>&1 > compilation.log
g++ myprogram.cpp 2>&1 | more

and we can still use tee:

g++ myporogram.cpp 2>&1 | tee compilation.log









Error Messages

* Unfortunately, once you start writing your own code, you will almost certainly make some mistakes and get some error messages from the compiler.

This is likely to lead to two problems: reading the messages, and understanding the messages.
Capturing the Error Messages



*Unless you are a far better programmer than I, you will not only get error messages, you will get so many that they overflow your telnet/xterm window.

How you handle this problem depends upon what command shell you are running, but there are two general approaches. You can use redirection and pipes to send the error messages somewhere more convenient or you can use programs that try to capture all output from a running program (i.e., the compiler).

*We've talked before about how many Unix commands are "filters", working from a single input stream and producing a single output stream. Actually, there are 3 standard streams in most operating systems: standard input, standard output, and standard error. These generally default to the keyboard for standard input and the screen for the other two, unless either the program or the person running the program redirects one or more of thes streams to a file or pipes the stream to / from another program.




Linkage Flags

-L directory                 Add directory to the list of places searched for precompiled libraries.
-llibname                   Link with the precompiled library liblibname.a


Compilation Flags

-c                               compile only, do not link
-o filename                  Use filename as the name of the compiled program
-Dsymbol-value             Define symbol during compilation.
-g                              Include debugging information in compiled code
                                 (required if you want to be able to run the gdb degugger).
-O                              Optimize the compiled code (produces smaller, faster programs
                                 but takes longer to compile)
-l directory                  Add directory to the list of places searched when a "system"
                                include (#include ...) is encountered.


Compiling With Multiple Non-Header Files

* A typical program will consist of many .cpp files. (See Figure 7.1, "Building 1 program from many files") Usually, each class or group of utility functions will have their definitions in a separate .cpp file that defines everything declared in the corresponding .h file. The .h file can then be #included by many different parts of the program that use those classes or functions, and the  .cpp file can be separately compiled once, then the resulting object code file is linked together with the object code from other .cpp files to form the complete program.

* Splitting the program into pieces like this helps, among other things, divide the responsibility for who can change what and reduces the amount of compilation that must take place after a change to a function body.

* When you have a program consisting of multiple files to be compiled separately, add a -c option to each compilation. This will cause the compiler to generate a .o object code file instead of an executable. Then invoke the compiler on all the .o files together without the -c to link them together and produce an executable:

g++ -g -c file1.cpp
g++ -g -c file2.cpp
g++ -g -c file3.cpp
g++ -g -o programName file1.o file2.o file3.o

* (If there are no other .o files in that directory, the last command can often be abbreviated to "g++ -o programName -g *.o".) The same procedure works for the gcc compiler as well.

Actually, you don't have to type separate compilation commands for each file. You can do the whole thing in one step:

g++ -g -o programName file1.cpp file2.cpp file3.cpp

* But the step-by-step procedure is a good habit to get into. As you begin debugging your code, you are likely to make changes to only one file at a time. If, for example, you find and fix a bug in file2.cpp, you need to only recompile that file and relink:

g++ -g -c file2.cpp
g++ -g -o programName file1.o file2.o file3.o

Use an editor (e.g., emacs) to prepare the follwing files:

hellomain.cpp

#include <iostream>
#include "sayhello.h"

using namespace std;

int main()
{
   sayHello();
   return 0;
}


sayhello.h

#ifndef SAYHELLO_H
#define SAYHELLO_H

void sayHello();

#endif

sayhello.cpp

#include <iostream>;
#include "sayhello.h"

using namespace std;

void sayHello()
  count << "hello in 2parts!" << endl;
}

* To compile and run these, give the commands:

g++ -g -c sayhello.cpp
g++ -g -c hellomain.cpp
ls
g++ -g -o hello1 sayhello.o hellomain.o
ls
./hello1


* Note, when you do the first ls, tht the first two g++ invocations created some .o files.

Alternatively, you can compile these in one step. Give the command

rm hello1 *.o
ls

just to clean up after the previous steps, then try compiling this way:

g++ -g -o hello2 hellomain.cpp sayhello.cpp
ls 
./hello2

* An even better way to manage multiple source files is to use the make command.
Some Useful Compiler Options

* Another useful option in these compilers is -D. If you add an option -Dname=value, then all occurrences of the identifier name in the program will be replaced by value. This can be useful as a way of customizing programs without editing them. If you use this option without a value, -Dname, then the compiler still notes that name has been "defined". This is useful in conjunction with compiler directive ifdef, which causes certain code to be compiled only if a particular name is defined. For example, many programmers will insert debugging output into their code this way:

...
x= f(x,y,z);
#ifdef DEBUG
   cerr << "the value of X is: " << x <<endl;
#endif
y=g(z,x);
...

* The output statement in this code will be ignored by the compiler unless the option -DDEBUG is included in the command line when the compiler is run.[38]

Sometimes your program may need functions from a previously-compiled library. For example, the sqrt and other mathematical functions are kept in the "m" library (the filename is actually libm.a). To add functions from this library to your program, you would use the "-lm" option. (The "m" in "-lm" is the library name.) this is a linkage option, so it goes at the end of the command:

g++ -g -c file1.cpp
g++ -g -c file2.cpp
g++ -g -c file3.cpp
g++ -g -o programName file1.o file2.o file3.o -lm

The general form of gcc/g++ commands is g++ compilation-option files linker-options Here is a summary of the most commonly used options for gcc/g++:

 





























Compiling a Program with Only One Non-Header File

Use an editor (e.g., emacs) to prepare the following files:

hello.cpp

#include <iostream>

using namespace std;

int main()
{
   count << "Hello from C++!" << endl;
   return 0;
}

hello.c

#include<stdio.h>
int main()
{
   printf("Hello from C!\n");
   return 0;
}

To compile and run these, give the commands:

g++ -g hello.cpp
ls

Notice that a file a.out has been created.

./a.out
gcc -g hello.c
./a.out

* The compiler generates an executable program called a.out If you don't like that name, you can use the mv command to rename it.

Alternatively, use a -o option to specify the name you would like for the compiled program:

g++ -g -o hello1 hello.cpp
./hello1
gcc -g -o hello2 hello.c
./hello2

* In the example above, we placed "./" in front of the file name of our compiled program to run it, in general, running prgrams is no different from running ordinary Unix commands. You just type

pathToProgramOrCommand parameters

In fact, almost all of the "commands" that we have used in this course are actually programs that were compiled as part of the installation of the Unix operation system.

* As we have noted earlier, we don't usually give the command/program name as a lengthy file path. We say, for example, "ls" instead of "/bin/ls". That works because certain directories, such as /bin, are automatically searched for a program of the appropriate name. This set of directories is referred to as your execution path. Your account was set up so that the directories holding the most commonly used Unix commands and programs are already in the execution path. You can see your path by giving the command

* echo $PATH

One thing that you will likely find i that your $PATH probably does not include ".", your current directory. Placing the current directory into the $PATH is considered a (minor) security risk, but that means that, if we had simply typed "a.out" or "hello", those programs would not have been found because the current directory is not in the search path. Hence, we gave the explicit path to the program files, "/a.out" and "./hello".









What Goes into a Header File? What Goes Into a Non-Header File?

* Pretty much everyghing that has a "name" in C++ must be declared before you can use it. Many of these things must also be defined, but that can generally be done at a much later time.

* You declare a name by saying what kind of thing it is:

  const int MaxSize;                 //  declares a constant
  extern int v;                         // declares a variable
  void foo (int formalParam);     // declares a function(and a formal parameter)
  class Bar{...};                        // declares a class
  typedef Bar* BarPointer;        // declares a type name


* In most cases, once you have declared a name, you can write code that uses it. Furthermore, a program may declare the same thing any number of times, as long as it does so consistently. That's why a single header file can be included by several different non-header files that make up a program - header files contain only declarations.

* You define constants, variables, and functions as follows:

const int MaxSize = 1000;                        // defines a constant
int v;                                                   // defines a variable
void foo(int formalParam){++formalParam;} //defines a function

* A definition must be seen by the compiler once and only once in all the compilations that get linked together to form the final program. A definition is itself also a declaration (i.e., if you define something that hasn't been declared yet, that's OK. The definition will serve double duty as declaration and definition.).

* When a non-header file is compiled, we get an object-code file, usually ending in ".o". These are binary files that are "almost" executable - for some variables and function, instead of the actual address of that variable/function; they still have its name. This happens when the variable or function is declared but not defined in that non-header file ( after expansion of #includes by the pre-processor).

* That name will be assigned an address only when a file containing a definition of that name is compiled. And that address will only be recorded in the object code file corresponding to the non-header source file where the name was defined.

* The complete executable program is then produced by linking all the object code files together. The job of the linker is to find. for each name appearing in the object code, the address that was eventually assigned to that name, make the substitution, and produce a true binary executable in which all names have been replaced by addresses.

* Understanding this difference and how the entire compilation/build process works (Figure 7.1, "Building 1 program from many files") can help to explain some common but confusingly similar error messages:

If the compiler says that a function is undeclared, it means that you tried to use it before presenting its declaration, or forgot to declare it at all.

* The compiler never complains about definitions, because an apparently missing definition might just be in some other non-header file you are going to compile later. but when you try to produce the executable program by linking all the compiled object code files produced by the compiler, the linker may complain that a symbol is undefined (none of the compiled files provided a definition) or is multiply defined (you provided two definitions for one name, or somehow compiled the same definition into more than one object-code file).

* For example, if you forget a function body, the linker will eventually complain that the function is undefined. If you put a variable or function definition in a .h file and include that file from more than one place, the linker will complain that the name is multiply defined.

























Compiling and Executing Go Programs

* Now that you know how to create and edit files, you can generate new programs. The most commonly used languages in the CS Department at the moment are C++, C, and Java.

The most popular C++ and C compilers are g++ and gcc. 
The Structure of C++ and C Programs

* Although not really a Unix-specific topic, it's hard to discuss how to compile code under any operating system wityhout a basic understanding how programs are put together.

* The source code for a C++(or C) program is contained in a number of text files called source files. Very simple programs might be contained within a single source file, but as our programs grow larger and more complicated, programmers try to keep things manageable by splitting the code into multiple source files, no one of which should b terribly long.

* There are two dirrenrent kinds of source files: header files and not-header files. Header files are generally given names ending in ".h". Non-header files are generally given names ending in ".cpp" for C++ code and ".c" for C code.

* Header and non-header files are treated differently when we build programs. Each non-header file i compiled separately from the others (Figure 7.1, "Building 1 program from many files"). This helps keep the compilation times reasonable, particularly when we are fixing bugs in a program and may have changed only one or two non-header files. Only those changed files need to b recompiled.

* Header files are not compiled directly, Instead, header files are included into other source files via #include. In fact, when you invoke a C/C++ compiler, before the "real" compiler starts, it runs a pre-processor whose job is to handle the special instructions that begin with #. In the case of #include statements, the pre-processor simply grabs the relevant header file and sticks it content into the program right at the spot of the #include.


#include <iostream>
#incldue <string>

using namesapce std;
int main()
{
    string greeting = "Hello!";
    cout << greeting << endl;
    return 0;
}

* This can result in a dramatic increase in the amount of code that actually gets processed. The code shown here, for example, is pretty basic. But the #include statements bring in a entire library of I/O and string-related declarations from the C++ standard library. Here, for example, is the output of the pre-processor for one compiler. (If you look at the very end, you can recognize the main code for this program.)

* A header file can be #included from any number of other header and non-header files. That is, in fact, the whole point of having header files. Header files should contain declarations of things that need to be shared by multiple other source files. Non-header files should declare only things that do not need to be shared.

* As we go though all the compilation steps required to build a program, anything that appears in a non-header file will be processed exactly once by the compiler.
Anything that appears in a header file may be processed multiple times by the compiler.




















Go Programs

* A Go program can vary in length from 3 lines to millions of lines and it should be written into one or more text files with the extension ".go". For example, hello.Go.  You can use "vi" ", "vim" or any other text editor to write your Go program into a file.

Features Excluded Intentinally


* To keep the language simple and concise, the following features commonly available in other similar languages are omitted in Go:

1. Support for type inheritance
2. Support for method or operator overloading
3. Support for circular dependencies among packages
4. Support for pointer arithmetic
5. Support for assertions
6. Support for generic programming


Features of Go Programming

Binaries

* Go generates binaries for your applications with all the dependencies built-in. This removes the need for you to install runtimes that are necessary for running your application. This eases the task of deploying apoplications and providing necessary updates across thousands of ins tallations. With its support for multiple OS and processor architectures, this is a big win for the language.

Language Design

* The designers of the language made a conscious decision to keep the language simple and easy to understand. The entire specification is in a small number of pages and some interesting design decisions were made vis-a-vis Object-Oriented support in the language that keeps the features limited.

* Towards this, the language is opinionated and recommends an idiomatic way of achieving things. It prefers Composition over Inheritance and its Type System is elegant and allows for behavior to be added without tight coupling the components too much. In Go Language, "Do More with Less" is the mantra.

Powerful Standard Library

* Go comes with a powerful standard library, distributed as packages. This library caters to most components, libraries that developers have come to expect from 3rd party packages when it comes to other languages. A look at the Packages available in the standard library is good enough indication of the power available in them.


Package Management

* Go combines modern day developer workflow of working with Open Source projects and includes that in the way it manages external packages. Support is provided directly in the tooling to get external packages and publish your own packages in a set of easy commands.

Static Typing

* Go is a statically typed language and the compiler works hard to ensure that the code is not just able to compile correctly but other type conversions and compatibility are taken care of. This can avoid the problems that one faces in dynamically typed languages, where you discover the issues only when the code is executed.

Concurrency Support

* One area where the language shines is its first-class support for Concurrency in the language itself. If you have programming concurrency in other languages, you understand that it is quite complex to do so. Go Concurrency primitives via go routines and channels makes concurrent programming easy. Its ability to take advantage of multi-core processor architectures and efficient memory is one of the reasons while Go code is today running some of the most heavily used applications that are able to scale.

Testing Support

* Go Language brings Unit Testing right into the language itself. It provides a simple mechanism to write your unit tests in parallel with your code. The tooling also provides support to understand code coverage by your tests, benchmarking tests and writing example code that is used in generating your code documentation.

* Go has seen sighnificant adoption from large projects and due to its tooling, ecosystem and language design, programmers are steadily moving towards it, especially while building out infrastructure pieces. We expect that its popularity will continue to rise. Getting started with Go is straightforward and the Go Programming Language Home page has everything from installing the tool-chain to learning about Go.